3 Commits

Author SHA1 Message Date
lzl
cdd3f79c59 Merge branch 'branch_new' into branch_new_83 2025-12-16 10:01:20 +08:00
lzl
a593acba07 Merge branch 'branch_new' into branch_new_83 2025-12-10 18:12:01 +08:00
lzl
3c59e8bbce 83 2025-12-10 16:15:37 +08:00
597 changed files with 5881 additions and 22020 deletions

2
.idea/.name generated
View File

@@ -1 +1 @@
羽声语音
秘地

View File

@@ -5,7 +5,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -85,7 +84,6 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
getWindow().getDecorView().setBackgroundResource(R.mipmap.log_bj);
setContentView(getLayoutId());
doDone();
@@ -105,7 +103,7 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
// 注册背景更新监听器
BackgroundManager.getInstance().addListener(this);
// 尝试加载网络背景
// loadNetworkBackground();
loadNetworkBackground();
// 注册颜色变化监听器
ColorManager.getInstance().addColorChangeListener(this);
@@ -181,37 +179,28 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
protected void loadNetworkBackground() {
// 只有当已经有背景URL时才加载
int backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl();
getWindow().getDecorView().setBackgroundResource(backgroundUrl);
String backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl();
if (backgroundUrl != null && !backgroundUrl.isEmpty()) {
// 检查是否有已加载的drawable
Drawable cachedDrawable = BackgroundManager.getInstance().getBackgroundDrawable();
if (cachedDrawable != null) {
getWindow().getDecorView().setBackground(cachedDrawable);
} else {
// 加载网络背景
BackgroundManager.getInstance().loadBackgroundDrawable(this, new BackgroundManager.BackgroundLoadCallback() {
@Override
public void onLoadSuccess(Drawable drawable) {
getWindow().getDecorView().setBackground(drawable);
}
// String backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl();
// if (backgroundUrl != null && !backgroundUrl.isEmpty()) {
// // 检查是否有已加载的drawable
// Drawable cachedDrawable = BackgroundManager.getInstance().getBackgroundDrawable();
// if (cachedDrawable != null) {
// getWindow().getDecorView().setBackground(cachedDrawable);
// } else {
// // 加载网络背景
// BackgroundManager.getInstance().loadBackgroundDrawable(this, new BackgroundManager.BackgroundLoadCallback() {
// @Override
// public void onLoadSuccess(Drawable drawable) {
// getWindow().getDecorView().setBackground(drawable);
// }
//
// @Override
// public void onLoadFailed() {
// // 加载失败时使用默认背景
// getWindow().getDecorView().setBackgroundResource(R.mipmap.activity_bj);
// }
//
// @Override
// public void onLoadComplete(int resultId) {
//
// }
// });
// }
// }
@Override
public void onLoadFailed() {
// 加载失败时使用默认背景
getWindow().getDecorView().setBackgroundResource(R.mipmap.activity_bj);
}
});
}
}
}
@Override
@@ -224,7 +213,7 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
// 提供一个方法供子类调用用于设置背景URL
protected void setNetworkBackgroundUrl(String url) {
// BackgroundManager.getInstance().setBackgroundUrl(url);
BackgroundManager.getInstance().setBackgroundUrl(url);
}
@Override
@@ -267,14 +256,13 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
@Override
public void finish() {
EventBus.getDefault().unregister(this);
super.finish();
LogUtils.e(this.getComponentName()+"========finish");
}
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
// 移除背景更新监听器
BackgroundManager.getInstance().removeListener(this);
// 移除颜色变化监听器

View File

@@ -117,7 +117,6 @@ public class AppUpdateDialog extends BaseDialog<DialogAppUpdateBinding> implemen
mProgressDialog.dismiss();
}
try {
LogUtils.e("installAppSuccess",localPath);
AppUtils.installApp(localPath);
} catch (Exception e) {
Logger.e("installAppError", e);

View File

@@ -186,7 +186,7 @@ public class CirleListAdapter extends BaseQuickAdapter<CircleListBean, BaseViewH
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);
helper.getView(R.id.dy_content_tv).setVisibility(GONE);
} else {
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);
helper.getView(R.id.dy_lookmore_tv).setVisibility(VISIBLE);
helper.getView(R.id.dy_content_tv).setVisibility(VISIBLE);
}
helper.getView(R.id.dy_lookmore_tv).getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@@ -196,7 +196,7 @@ public class CirleListAdapter extends BaseQuickAdapter<CircleListBean, BaseViewH
TextView view = helper.getView(R.id.dy_content_tv);
int lineCount = view.getLineCount();
if (lineCount >= 7) {
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);
helper.getView(R.id.dy_lookmore_tv).setVisibility(VISIBLE);
helper.getView(R.id.dy_content_tv).getViewTreeObserver().removeOnPreDrawListener(this);//销毁
} else {
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);

View File

@@ -7,7 +7,6 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.GestureDetector;
import android.view.LayoutInflater;
@@ -153,25 +152,19 @@ public class GiftRoomAdapter extends BaseAdapter {
} else {
viewHolder.iv_gift_select.setVisibility(VISIBLE);
}
if (TextUtils.isEmpty(giftModel.getIcon())) {
viewHolder.im_heart.setVisibility(GONE);
}else {
viewHolder.im_heart.setVisibility(VISIBLE);
ImageUtils.loadHead(giftModel.getIcon(), viewHolder.im_heart);
}
// if (giftModel.getIs_cp() == 0 && giftModel.getIs_teacher() == 0 ) {//这是cp礼物
// viewHolder.im_heart.setVisibility(GONE);
// } else {
// if (viewHolder.im_heart != null) {
// viewHolder.im_heart.setVisibility(VISIBLE);
// if (giftModel.getIs_cp() == 1) {
// viewHolder.im_heart.setImageResource(R.mipmap.icon_heart);
// }else if (giftModel.getIs_teacher() == 1) {
// viewHolder.im_heart.setImageResource(R.mipmap.icon_teacher);
// }
// }
// }
if (giftModel.getIs_cp() == 0 && giftModel.getIs_teacher() == 0 ) {//这是cp礼物
viewHolder.im_heart.setVisibility(GONE);
} else {
if (viewHolder.im_heart != null) {
viewHolder.im_heart.setVisibility(VISIBLE);
if (giftModel.getIs_cp() == 1) {
viewHolder.im_heart.setImageResource(R.mipmap.icon_heart);
}else if (giftModel.getIs_teacher() == 1) {
viewHolder.im_heart.setImageResource(R.mipmap.icon_teacher);
}
}
}
/*

View File

@@ -26,7 +26,6 @@ import androidx.multidex.MultiDex;
import androidx.multidex.MultiDexApplication;
import com.alibaba.android.arouter.launcher.ARouter;
import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.LogUtils;
@@ -44,7 +43,6 @@ import com.tencent.qcloud.tuicore.TUILogin;
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
import com.xscm.moduleutil.bean.UserBean;
import com.xscm.moduleutil.bean.UserInfo;
import com.xscm.moduleutil.dialog.ConfirmDialog;
import com.xscm.moduleutil.event.AppLifecycleEvent;
import com.xscm.moduleutil.event.UnreadCountEvent;
import com.xscm.moduleutil.http.RetrofitClient;
@@ -77,7 +75,7 @@ import lombok.Setter;
* Created by cxf on 2017/8/3.
*/
public class CommonAppContext extends MultiDexApplication implements Application.ActivityLifecycleCallbacks {
public class CommonAppContext extends MultiDexApplication implements Application.ActivityLifecycleCallbacks {
private static CommonAppContext sInstance;
private static Handler sMainThreadHandler;
@@ -97,19 +95,17 @@ public class CommonAppContext extends MultiDexApplication implements Application
public boolean isShowAg;
public boolean isRoomJoininj = false;
public boolean isRoomJoininj=false;
public String playCover;
public boolean showSelf;//盲盒是否能送自己
public String playName;
private MqttConnect mqttConnect = null;
private MqttConnect mqttConnect=null;
// 添加后台状态标记
private boolean wasInBackground = false;
public boolean isMai = false;
public boolean isLogout = false;
public boolean isMai=false;
public void onAppBackground() {
wasInBackground = true;
@@ -127,24 +123,16 @@ public class CommonAppContext extends MultiDexApplication implements Application
private AppStateListener appStateListener;
private boolean isListeningUnreadCount = false;
public boolean onConnectFailed = false;//是否重连
public boolean onConnectFailed=false;//是否重连
@Getter
@Setter
public Map<String, Integer> onlineMap = new HashMap<>();
public Map<String, Integer> onlineMap=new HashMap<>();
@Setter
@Getter
public UnreadCountEvent unreadCountEvent;
public static int selectRelease = 1;
public int is_open = 0;//主题的开关
public String appId = "com.qxcm.qxlive";
public String appVersionCode = "86";
public String appVersionName = "1.0.9.6";
@Override
public void onCreate() {
super.onCreate();
@@ -166,18 +154,14 @@ public class CommonAppContext extends MultiDexApplication implements Application
CrashHandler.init(this);
if (SpUtil.getShelf() != 0) {
if (SpUtil.getShelf()!=0) {
SpUtil.setShelf(1);
}
if (SpUtil.getTaskService() == 1){//当如果是正式服的时候,这里就变成可以设置成辅助服务器,当如果是测试服务的时候,就是变成了测试了,
selectRelease = 1;
}
//设置mqtt环境 false 测试环境 true 正式环境
// ExternalResConstants.INSTANCE.setIS_MQTT_RELEASE(false);
//设置http环境 false 测试环境 true 正式环境
ExternalResConstants.INSTANCE.setIS_HTTP_RELEASE(selectRelease);
ExternalResConstants.INSTANCE.setIS_HTTP_RELEASE(true);
currentEnvironment = ExternalResConstants.INSTANCE.HTTP_PATH();
initialization();
@@ -225,38 +209,6 @@ public class CommonAppContext extends MultiDexApplication implements Application
}
}
public void dialogHttp(){
new ConfirmDialog(ActivityUtils.getTopActivity(),
"提示",
"当前网络环境异常,请重试",
"确认",
"取消",
v -> {
// 点击“确认”按钮时执行删除操作
selectRelease = 3;
initHttp();
},
v -> {
selectRelease = 3;
initHttp();
// 点击“取消”按钮时什么都不做
}, false, 0).show();
}
public void initHttp(){
ExternalResConstants.INSTANCE.setIS_HTTP_RELEASE(selectRelease);
currentEnvironment = ExternalResConstants.INSTANCE.HTTP_PATH();
try {
RetrofitClient.INSTANCE=null;
RetrofitClient.getInstance();
clearLoginInfo();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
// 更新未读消息数的方法
private void updateUnreadMessageCount() {
V2TIMManager.getConversationManager().getTotalUnreadMessageCount(new V2TIMValueCallback<Long>() {
@@ -276,19 +228,17 @@ public class CommonAppContext extends MultiDexApplication implements Application
// 通知未读数变化的方法可以发送广播或EventBus事件
private void notifyUnreadCountChanged(long unreadCount) {
UnreadCountEvent event = unreadCountEvent;
if (event == null) {
event = new UnreadCountEvent();
UnreadCountEvent event =unreadCountEvent;
if (event==null){
event=new UnreadCountEvent();
}
event.setALong(unreadCount);
// 使用EventBus通知
CommonAppContext.getInstance().setUnreadCountEvent(event);
EventBus.getDefault().post(event);
EventBus.getDefault().post(event);
}
/**
* 检查网络是否可用
*
* @return true表示网络可用false表示网络不可用
*/
public boolean isNetworkAvailable() {
@@ -807,16 +757,12 @@ public class CommonAppContext extends MultiDexApplication implements Application
if (mqttConnect != null){
mqttConnect.close();
mqttConnect = null;
}
isLogout = true;
// 发送广播通知所有Activity刷新状态
// Intent refreshIntent = new Intent("com.xscm.moduleutil.ACTION_USER_LOGOUT");
// sendBroadcast(refreshIntent);
ActivityUtils.finishAllActivities();
Intent refreshIntent = new Intent("com.xscm.moduleutil.ACTION_USER_LOGOUT");
sendBroadcast(refreshIntent);
Intent intent = new Intent("com.qxcm.qxlive.LAUNCH_PAGE");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);

View File

@@ -4,7 +4,7 @@ import com.xscm.moduleutil.utils.config.EnvironmentEnum
object ExternalResConstants {
//================================================================================MQTT======================================================================================
//================================================================================MQTT======================================================================================
// var IS_MQTT_RELEASE = true
// val MQTT_PATH_DEBUG = "tcp://1.13.181.248"
// val MQTT_PATH_RELEASE = "tcp://1.13.101.98"
@@ -17,15 +17,12 @@ object ExternalResConstants {
// }
// }
//================================================================================HTTP======================================================================================
var IS_HTTP_RELEASE: Int = 1 //0 测试环境 1 正式环境 2 辅助环境
val HTTP_PATH_DEBUG: EnvironmentEnum = EnvironmentEnum.TEST
val HTTP_PATH_RELEASE: EnvironmentEnum = EnvironmentEnum.PRODUCTION
val HTTP_AUXILIARY: EnvironmentEnum = EnvironmentEnum.Auxiliary
var IS_HTTP_RELEASE = true
val HTTP_PATH_DEBUG:EnvironmentEnum = EnvironmentEnum.TEST
val HTTP_PATH_RELEASE:EnvironmentEnum = EnvironmentEnum.PRODUCTION
fun HTTP_PATH(): EnvironmentEnum {
return if (IS_HTTP_RELEASE == 1) {
return if (IS_HTTP_RELEASE) {
HTTP_PATH_RELEASE
} else if (IS_HTTP_RELEASE == 3) {
HTTP_AUXILIARY
} else {
HTTP_PATH_DEBUG
}

View File

@@ -1,11 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2026/1/14 18:47
* 用途app配置的客服用户id和name
*/
class AppCustomerBean {
var user_id: String = ""
var user_name: String = ""
}

View File

@@ -1,8 +0,0 @@
package com.xscm.moduleutil.bean
import java.io.Serializable
class BeforeJoinRoomCheckBean :Serializable {
var room_id:String? = null
var msg:String? = null
}

View File

@@ -1,28 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2026/1/7 19:47
* 用途:
*/
class BlackRoomBean {
var id: Int = 0
var p_room_id: Int = 0
var room_id: Int = 0
var user_id: Int = 0
var meet_user_id: Int = 0
var end_time: Int = 0
var createtime: Int = 0
var status: Int = 0
var heart_value: String? = ""
/* "id": 1,
"p_room_id": 6065,
"room_id": 6071,
"user_id": 20142,
"meet_user_id": 20137,
"end_time": 1767957473,
"createtime": 1767784373,
"status": 1,
"heart_value": null*/
}

View File

@@ -16,6 +16,6 @@ public class BlackUserBean {
private int sex;
private String user_code;
private int is_online;
private int is_follow;// 是否关注 0:未关注 1已关注 2别人关注了你你没有关注别人这个2只会在粉丝中使用
private int is_follow;
private List<String> icon;
}

View File

@@ -1,20 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2025/12/21 11:37
* 用途:盲盒转盘状态
*/
class BlindBoxStatus {
var gift_bag_id: Int = 0
var name: String = ""
var status: Int = 0 //0关闭 1开启
var status_str: String = ""
var icon: String = ""
// "gift_bag_id": 11,
// "name": "岁月之城",
// "status": 1,
// "status_str": "开启中",
// "icon": null
}

View File

@@ -1,174 +0,0 @@
package com.xscm.moduleutil.bean
import com.google.gson.annotations.SerializedName
import java.util.ArrayList
/**
* 项目名称:羽声语音
* 时间2026/1/4 10:22
* 用途:装扮价格详情
*/
class DecorateDetailBean {
// 用户信息服务端返回的user_info字段
@SerializedName("user_info")
var userInfo: UserInfoDecorate? = UserInfoDecorate()
// 装饰商品核心信息服务端返回的decorate字段
@SerializedName("decorate")
var decorate: Decorate? = null
/**
* 用户信息内部类对应服务端user_info
*/
class UserInfoDecorate {
@SerializedName("user_id")
var userId: Int = 0
@SerializedName("user_coin")
var userCoin: String = ""
}
/**
* 装饰商品核心信息对应服务端decorate直接解析服务端返回数据
* 注意与之前适配器的Item模型解耦该类仅负责接收服务端数据不承担适配器布局类型职责
*/
class Decorate {
@SerializedName("title")
var title: String = "" // 商品名称(如“粉色花头”)
@SerializedName("price")
var price : String =""
@SerializedName("base_image")
var base_image : String =""
@SerializedName("price_list")
var priceList: List<PriceListBean> = ArrayList() // 价格/时长列表(服务端返回数组)
}
/**
* 价格/时长明细bean对应服务端price_list中的单个对象
* 可直接解析服务端返回的每个价格项数据同时适配适配器的PriceItem模型
*/
class PriceListBean {
@SerializedName("price")
var price: String = "" // 现价
@SerializedName("original_price")
var originalPrice: String = "" // 原价
@SerializedName("discount")
var discount: String = "" // 折扣如“5.0”)
@SerializedName("day")
var day: Int = 0 // 有效天数
@SerializedName("month")
var month: String = "" // 有效月数
@SerializedName("end_time")
var endTime: String = "" // 有效期截止时间
}
// ---------------------- 适配器适配相关:转换方法 + 适配器所需模型 ----------------------
/**
* 适配器的Item数据模型密封类区分单行/多选项)
* 与服务端数据模型解耦专门用于RecyclerView适配器布局
*/
sealed class DecorateAdapterItem {
// 单行信息类型(如“商品价格”“有效期至”)
data class SingleItem(
val label: String, // 左侧标签文字
val content: String // 右侧内容文字
) : DecorateAdapterItem()
// 购买时长多选项类型(承载所有时长选项)
data class MultiOptionItem(
val options: List<PriceListBean> // 直接复用PriceListBean已适配服务端数据
) : DecorateAdapterItem()
// type=12专用购买次数加减按钮
data class BuyCountItem(
val initialCount: Int,
val unitPrice: String
) : DecorateAdapterItem()
}
/**
* 转换方法将服务端数据Decorate转换为适配器所需数据列表List<DecorateAdapterItem>
* 实现服务端数据与适配器的桥接,方便适配器直接使用
* @param defaultSelectedPos 默认选中的时长选项下标默认0即第一个选项
*/
fun convertToAdapterData(
decorate: Decorate?,
defaultSelectedPos: Int = 0
): List<DecorateAdapterItem> {
val adapterDataList = mutableListOf<DecorateAdapterItem>()
if (decorate == null ) {
return adapterDataList
}
if ( decorate.priceList.isEmpty()){
// ---------- type=12解析单个字段无price_list新增购买次数、商品总价 ----------
val unitPrice = decorate.price// 直接取Decorate的singlePrice服务端返回的单价
val unitPriceStr = unitPrice // 格式化单价,避免小数异常
// 2. 商品单价单行项取decorate.singlePrice
adapterDataList.add(
DecorateAdapterItem.SingleItem(
label = "商品单价",
content = unitPriceStr
)
)
// 3. 购买次数type=12专用初始数量1传入单价用于计算总价
adapterDataList.add(
DecorateAdapterItem.BuyCountItem(
initialCount = 1,
unitPrice = unitPrice
)
)
// 4. 商品总价单行项初始单价×1
adapterDataList.add(
DecorateAdapterItem.SingleItem(
label = "商品总价",
content = unitPriceStr // 初始总价=单价×1
)
)
}else {
// 安全获取默认选中项(防止下标越界)
val selectedPos = if (defaultSelectedPos in decorate.priceList.indices) {
defaultSelectedPos
} else {
0
}
val selectedPriceItem = decorate.priceList[selectedPos]
// 1. 添加“商品价格”单行项(取选中项的现价)
adapterDataList.add(
DecorateAdapterItem.SingleItem(
label = "商品价格",
content = "${selectedPriceItem.price}" // 拼接货币符号,优化展示
)
)
// 2. 添加“有效期至”单行项(取选中项的截止时间)
adapterDataList.add(
DecorateAdapterItem.SingleItem(
label = "有效期至",
content = selectedPriceItem.endTime
)
)
// 3. 添加“购买时长”多选项(承载所有价格/时长列表)
adapterDataList.add(
DecorateAdapterItem.MultiOptionItem(
options = decorate.priceList
)
)
}
return adapterDataList
}
}

View File

@@ -1,11 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2025/12/30 9:44
* 用途:节日主题接口
*/
class FestivalThemeBean {
var is_open : Int = 0 //主题开关
var theme_name : String = "" //主题名称
}

View File

@@ -41,8 +41,7 @@ public class GiftBean {
public boolean isSameGiftFromSameSender(GiftBean other) {
if (other == null) return false;
return Objects.equals(gift_id, other.gift_id) &&
Objects.equals(senderName, other.senderName) &&
Objects.equals(nickname,other.nickname);
Objects.equals(senderName, other.senderName);
}
// 生成礼物唯一键

View File

@@ -61,8 +61,7 @@ public class GiftBoxBean {
private int task_type_id;
private String task_type_name;
private int is_lock;//锁:0 不开启锁 1 开启锁
private int wait_reward_num;//待领取奖励数量
@Data
public static class DailyTasksBean {

View File

@@ -1,53 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2026/1/3 10:13
* 用途:群聊实体类
*/
class GroupBean {
var guild_id: String = ""
var guild_cover: String = ""
var is_deacon: Int = 0 //是否是群主 1是 ,其他的不是
var user_list: List<GroupUserBean> = ArrayList()
var name: String = ""
var notification: String = ""
var mute_all_member : Int = 0 //是否全体禁言 1是 0不是
class GroupUserBean {
var is_online: Int = 0 //是否在线 1在线 0不在线
var market_value: Int = 0 //身价
var nickname: String = ""
var avatar: String = ""
var user_code: String = ""
var user_id: Int = 0
var createtime: String = ""
var is_self: Int = 0 //是否是本人 1是 0不是
var role: String = ""
var role_str: String = ""
var in_room_id: Int = 0 //是否在房间内 1在 0不在
var is_mute: Int = 0 //是否被禁言 1是 0不是
}
/*"guild_id": "f627",
"guild_cover": "https://yusheng-1369267578.cos.ap-guangzhou.myqcloud.com/images/android_images/325ee1f528343bb09ddc086b2b83b190.jpg",
"is_deacon": 1,
"user_list": [
{
"is_online": 1,
"market_value": 28,
"nickname": "🥭芒的很",
"avatar": "https://yusheng-1369267578.cos.ap-guangzhou.myqcloud.com/images/ios_images/1764941796523.jpeg",
"user_code": "10001",
"user_id": 21211,
"createtime": "2025-12-31 13:20:28",
"is_self": 0,
"role": "Member",
"role_str": "普通群成员",
"in_room_id": 0
}
],
"name": "美丽的眼神的家族",
"notification": ""*/
}

View File

@@ -1,13 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2026/1/3 14:07
* 用途:群成员列表
*/
class GroupUserListBean {
var page : String=""
var limit : String=""
var count : String=""
var list : List<GroupBean.GroupUserBean>?= ArrayList()
}

View File

@@ -20,7 +20,6 @@ public class MusicSongBean implements Serializable {
private String duration;//播放时长
private int sort;//
private String user_id;
private String user_code="";
private String nickname;
private String avatar;
private String dress;

View File

@@ -54,7 +54,6 @@ public class MyRoomBean {
private String come_count; //房间进入数
private Double today_income; //今日收益;
private int earnings_ratio;//房间收益比例
private String lucky_water="";//房间幸运流水
@Data
static class CpRoom {

View File

@@ -1,57 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2026/1/3 18:44
* 用途:装扮列表
*/
class PersonaltyListBean {
var did: Int =0 // 装扮id
var title: String = "" // 装扮名称
var type: Int = 0 // 1头像框 2坐骑 3资料展示特效 4光圈 5气泡 6个人靓号 7房间靓号 8工会靓号 100热门
var base_image: String = "" // 展示图片
var play_image: String = "" // 播放图像
var price: Int = 0 // 实际价格(金币)
var special_num: Int = 0 // 靓号
var original_price: Int = 0 // 原价
var discount: Double = 0.0 // 折扣
var discount_str: String = "" // 折扣字段
/* title
装扮名称
type
类型1头像框 2坐骑 3资料展示特效 4光圈 5气泡 6个人靓号 7房间靓号 8工会靓号 100热门
base_image
展示图片
play_image
播放图像
price
实际价格(金币)
special_num
靓号
original_price
原价
discount
折扣
discount_str
折扣字段*/
}

View File

@@ -1,13 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2026/1/6 14:25
* 用途:
*/
class PitTimeRespBean {
var time: Int = 0
var time_str: String = ""
/* "time": 5,
"time_str": "5分钟"*/
}

View File

@@ -1,11 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2025/12/30 18:02
* 用途:红包配置信息接口
*/
class RedPacketConfig {
var red_packet_min_amount : Int = 0 //发红包最小金额
var red_packet_fee : Int = 0 //发红包手续费
}

View File

@@ -4,7 +4,7 @@ import lombok.Data;
@Data
public class RevenueBean {
private int id;
private String id;
private String user_id;
private String change_type;
private String change_type_name;

View File

@@ -30,7 +30,7 @@ public class RoomMessageEvent extends BaseEvent {
public static class T {
private String text;
private String GiftNum;
private String pit_number;//麦位 酒吧房的情况下这个是抱麦的number
private String pit_number;//麦位
private String jia_jia;//坐骑
private UserInfo FromUserInfo;//从me
private UserInfo ToUserInfo;// 到you
@@ -47,13 +47,13 @@ public class RoomMessageEvent extends BaseEvent {
private List<RoomAuction.AuctionListBean> auction_list; //拍卖列表
private long duration;//时间
private RoomAuction.AuctionListBean recipient;//是否成功,有值的是成功的,没有值的时候,是失败的
private int type;//拍卖者1上麦、2下麦 暴币的时候1是大奖 2是小奖 在酒吧房的时候, 0没有选择自定义礼物 1选择了自定义礼物
private int type;//拍卖者1上麦、2下麦
private String hot_value;
private String SendRoomId;//发起者所在的房间ID
private String AcceptRoomId;//接收者所在的房间id
private String PkId;
private String room_id;//当type==1的时候。这个roomId是对方的房间id 当是酒吧房的时候就是需要进入的小房间的id
private String user_id = ""; //当是酒吧房的时候,这个值就是要进入小黑屋的房主信息
private String room_id;//当type==1的时候。这个roomId是对方的房间id
private String user_id = "";
private String pk_end_times;//pk结束时间
private List<RoomPitBean> userCharmList;
@@ -114,10 +114,6 @@ public class RoomMessageEvent extends BaseEvent {
private String status = "";
private String from_id = "";
private String play_image;//暴币播放动画地址
private String meet_user_id="";//当是酒吧房的时候就是被约的用户id
}
@Data

View File

@@ -13,7 +13,7 @@ public class RoonGiftModel {
private String gift_name;//礼物名称
private String base_image;//礼物图片
private String gift_price;//礼物价格
private String gift_id="";//礼物id
private String gift_id;//礼物id
private String gift_bag_name;
private String rule;
private String rule_url;
@@ -34,18 +34,9 @@ public class RoonGiftModel {
private int activities_id;//4盲盒 5天空之境
private int gift_bag;//10天空之境 11岁月之城 12时空之巅
private int is_lock;//爵位礼物 0不锁 1
private String icon="";//礼物标签图片
private int is_cp;//1:是 0不是 是不是cp心动礼物
private int is_teacher;//1:是 0不是 是不是师徒礼物
//下面是在酒吧房使用的参数
private int id;
private String gift_remark_name="";//用户设置的礼物内容
private String user_wallet_coin;//当前的钱包金币数
public boolean isCan_send_self() {
if ( isManghe()) {
return true;

View File

@@ -1,11 +0,0 @@
package com.xscm.moduleutil.bean
/**
* 项目名称:羽声语音
* 时间2025/12/16 11:35
* 用途:任务未领取角标
*/
class TasksMessage {
var num: Int=0
var not_received_tasks_num : Int=0 //任务未领取奖励数 这是心跳中返回的参数,用于展示任务未领取角标,是在房间内展示的
}

View File

@@ -1,8 +1,5 @@
package com.xscm.moduleutil.bean;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.base.CommonAppContext;
import lombok.Data;
/**
@@ -12,115 +9,17 @@ import lombok.Data;
*/
@Data
public class ThemeBean {
private int is_open;
private String theme_name;
private String theme_color="#22BB79";//主题颜色
private String theme_color;//主题颜色
private String file_url;//
private String auxiliary_color;//
private String btn_text_color="#3ABC6D";//按钮文字颜色
private int app_bg;//app背景图
private int home_sel;//首页选中
private int home_nor;//首页未选中
private int find_sel;//广场选中
private int find_nor;//广场未选中
private int msg_sel;//消息选中
private int msg_nor;//消息未选中
private int mine_sel;//我的选中
private int mine_nor;//我的未选中
public int getIs_open() {
CommonAppContext.getInstance().is_open = is_open;
return is_open;
}
public void setIs_open(int is_open) {
this.is_open = is_open;
CommonAppContext.getInstance().is_open = is_open;
}
public String getTheme_color() {
return "#22BB79";
}
public String getFile_url() {
return file_url;
}
public String getAuxiliary_color() {
return auxiliary_color;
}
public String getBtn_text_color() {
// if (CommonAppContext.getInstance().is_open == 1){
// return "#FF663B";
// }
return "#FFFFFF";
}
public int getApp_bg() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.bg_dark;
}else {
return R.mipmap.activity_bj;
}
}
public int getHome_sel() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_sy_select;
}
return R.mipmap.tab_main_media_selected;
}
public int getHome_nor() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_sy_notselect;
}
return R.mipmap.tab_main_media_unselected;
}
public int getFind_sel() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_dt_select;
}
return R.mipmap.icon_me_trend_select;
}
public int getFind_nor() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_dt_notselect;
}
return R.mipmap.icon_me_trend_unselect;
}
public int getMsg_sel() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_xx_select;
}
return R.mipmap.icon_news_select;
}
public int getMsg_nor() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_xx_notselect;
}
return R.mipmap.icon_news_un_select;
}
public int getMine_sel() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_wd_select;
}
return R.mipmap.icon_my_select;
}
public int getMine_nor() {
if (CommonAppContext.getInstance().is_open == 1){
return R.mipmap.icon_wd_notselect;
}
return R.mipmap.icon_my_un_select;
}
private String btn_text_color;//按钮文字颜色
private String app_bg;//app背景图
private String home_sel;//首页选中
private String home_nor;//首页未选中
private String find_sel;//广场选中
private String find_nor;//广场未选中
private String msg_sel;//消息选中
private String msg_nor;//消息未选中
private String mine_sel;//我的选中
private String mine_nor;//我的未选中
}

View File

@@ -98,8 +98,6 @@ public class UserInfo extends BaseEvent implements Serializable {
private Master master;
private int is_online;//是否在线 : 1在线 2离线
private int had_custom_gift;//是否显示设置了自定义礼物 0没有 1
@Data
public static class Master implements Serializable {

View File

@@ -11,7 +11,7 @@ public class WalletBean {
private String id;
private String user_id;
private String coin="0";//金币
private String coin;//金币
private String earnings;//钻石
private String url;//灵活就业合作伙伴协议
private String title;//状态

View File

@@ -11,21 +11,10 @@ public class EMMessageInfo implements MultiItemEntity {
public static final int QXRoomMessageTypeJoin = 1001;
/// 用户退出房间
public static final int QXRoomMessageTypeQuit = 1002;
//================================================================================================麦上变化=================================================================
/// 用户上麦
public static final int QXRoomMessageTypeUpSeat = 1003;
/// 用户下麦
public static final int QXRoomMessageTypeDownSeat = 1004;
/// 拍卖者被拉上麦
public static final int QXRoomMessageTypeAuctionIsUp = 1022;
/// 竞拍开始,竞拍麦位发生变化
public static final int QXRoomMessageTypeAuctionIsStart = 1024;
/// 互娱 麦位发生变化
public static final int QXRoomMessageTypeSeatDidChanged = 1053;
/// 房间内换麦
public static final int QXRoomMessageTypehm = 1039;
//==============================================================================================end=================================================================
/// 房间收到礼物
public static final int QXRoomMessageTypeGift = 1005;
/// 设置管理员
@@ -59,11 +48,12 @@ public class EMMessageInfo implements MultiItemEntity {
public static final int QXRoomMessageTypeRoomUpdate = 1020;
/// 清除魅力值
public static final int QXRoomMessageTypeRoom = 1021;
/// 拍卖者被拉上麦
public static final int QXRoomMessageTypeAuctionIsUp = 1022;
/// 拍卖者拍卖开始
public static final int QXRoomMessageTypeAuctionIsSelected = 1023;
/// 竞拍开始,竞拍麦位发生变化
public static final int QXRoomMessageTypeAuctionIsStart = 1024;
/// 竞拍结束
public static final int QXRoomMessageTypeAuctionIsEnd = 1025;
/// 主持延时
@@ -111,7 +101,8 @@ public class EMMessageInfo implements MultiItemEntity {
public static final int QXRoomMessageTypeRoomFriendCreateRelation = 1051;
/// 私密小屋结束时间发生延时
public static final int QXRoomMessageTypeCabinTimeDelay = 1052;
/// 麦位发生变化
public static final int QXRoomMessageTypeSeatDidChanged = 1053;
/// 心动值发生变化
public static final int QXRoomMessageTypeHeartDidChanged = 1054;
/// 小黑屋有人退出房间
@@ -138,7 +129,8 @@ public class EMMessageInfo implements MultiItemEntity {
//已点歌曲数量
public static final int QXRoomMessageTypeSongerNum = 1072;
/// 房间内换麦
public static final int QXRoomMessageTypehm = 1039;
public static final int QXRoomMessageTypeCPText = 1080;//CP特效进入房间的特效
/// 签约开始
public static final int QXRoomMessageTypeSignStartText = 1090;
@@ -158,20 +150,6 @@ public class EMMessageInfo implements MultiItemEntity {
/// 被签约者提示弹窗
public static final int QXRoomMessageTypeSignTipText = 1094;
/// 暴币展示动画列表
public static final int QXRoomMessageTypeSignChat = 1100;
/// 酒吧房撩ta推送
public static final int QXRoomMessageTypeFlirtatious = 1200;
/// 进入酒吧房的小黑屋
public static final int QXRoomMessageTypeFlirtatiousRoom = 1201;
/// 酒吧房抱麦推送
public static final int QXRoomMessageTypeFlirtatiousRoomPush = 1202;
/// 酒吧房设置了自定义礼物推送
public static final int QXRoomMessageTypeFlirtatiousRoomCustom = 1203;
private RoomMessageEvent emMessage;
private int custom = 0;
@@ -226,11 +204,9 @@ public class EMMessageInfo implements MultiItemEntity {
case QXRoomMessageTypeRoomFriendPartDidChanged:
case QXRoomMessageTypeSeatDidChanged:
case QXRoomMessageTypehm:
case QXRoomMessageTypeSignChat:
return 1;
case QXRoomMessageTypeRoomOMh:
case QXRoomMessageTypeGift:
case QXRoomMessageTypeFlirtatious:
return 3;
case 1:
case 2:

View File

@@ -75,7 +75,7 @@ public class RoomBean implements Serializable {
private String room_name;//房间名称
private String room_cover;//房间封面
private String room_intro;//房间公告
private String type_id;//房间类型 1:点唱(pk) 2拍卖真爱拍小黑屋 3/4交友 6小黑屋 7:互娱 8交友 10:签约 11:酒吧房
private String type_id;//房间类型 1:点唱(pk) 2拍卖真爱拍小黑屋 3/4交友 6小黑屋 7:互娱 8交友 10:签约
private String type_name;//房间类型名称
private String user_id;//房主id
private String label_id;//类型id 2:ktv type:1/3/4/8
@@ -89,7 +89,6 @@ public class RoomBean implements Serializable {
private int queue_number;//排麦队列人数
private HeadlineBean head_line;
private int sexy_coin;//酒吧房撩的金币
private String room_code;
private String popularity;

View File

@@ -26,7 +26,7 @@ public class RoomInfoResp implements Serializable {
private RoomOrderDemand demand;//嘉宾需求
private int rejoin;
private int is_show_self;//盲盒是否送自己
private MusicSongBean song_user_info;//ktv
private MusicSongBean song_user_info;
private MusicSongBean nextInfo;
private RoomAuction room_auction;//拍卖房信息
private RoomCpUserBean cp_user;

View File

@@ -50,6 +50,7 @@ public class RoomPitBean implements Serializable ,Cloneable{
private String dress;//麦位用户头像装扮
private String charm;//麦位上用户在当前房间的魅力值
private String room_id;
private String voice;
private String shutup;
@@ -76,10 +77,9 @@ public class RoomPitBean implements Serializable ,Cloneable{
private String nickname_color;//昵称颜色
private String mic_cycle;//麦圈
private boolean occupied;
private boolean imageType;//是否是演唱者
private String end_time;//倒计时结束时间 酒吧房
private int had_custom_gift;//是否显示设置了自定义礼物 0没有 1
public RoomPitBean clone(){
try {

View File

@@ -2,8 +2,6 @@ package com.xscm.moduleutil.bean.room;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import java.util.List;
import lombok.Data;
@Data
@@ -26,8 +24,6 @@ public class RoomSettingBean implements MultiItemEntity {
public static final int QXRoomSettingTypeRoomTypeLianG = 31;
//签约
public static final int QXRoomSettingTypeRoomTypeSIGNCONTRACT = 32;
//酒吧房
public static final int QXRoomSettingTypeRoomTypePUBROOM = 36;
/// 常用工具
/// 房间补贴
@@ -61,10 +57,6 @@ public class RoomSettingBean implements MultiItemEntity {
public static final int QXRoomSettingTypeRoomFloatingScreen = 29;//关闭飘屏
public static final int QXRoomSettingTypeRoomFloatingRed = 30;//红包
public static final int QXRoomSettingTypeRoomTheCityYears = 33;//岁月之城
public static final int QXRoomSettingTypeRoomTimeSpace = 34;//时空之巅
public static final int QXRoomSettingTypeRoomTimeRedSound = 35;//红包声音
public static final int ITEM_TYPE_DEFAULT = 0;
public static final int ITEM_TYPE_WITH_ICON = 1;
@@ -78,7 +70,7 @@ public class RoomSettingBean implements MultiItemEntity {
private boolean isSelected;//是否在麦位上
private boolean status;
private boolean select;//是否选中
private List<RoomSettingBean> children; // 新增子项列表
public RoomSettingBean(String name, String icon, String selectName, String selectIcon, int type, int read, boolean isSelected, boolean status, boolean select) {
this.name = name;
@@ -104,7 +96,6 @@ public class RoomSettingBean implements MultiItemEntity {
this.itemType = ITEM_TYPE_WITH_ICON;
}
}
// public void updateItemType() {
// switch (type) {
// case QXRoomSettingTypeRoomSubsidy:

View File

@@ -15,9 +15,7 @@ import android.view.Gravity;
import android.view.View;
import android.view.Window;
import com.alibaba.android.arouter.launcher.ARouter;
import com.alibaba.fastjson.JSON;
import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.adapter.BalanceRechargeAdapter;
@@ -31,7 +29,6 @@ import com.xscm.moduleutil.color.ThemeableDrawableUtils;
import com.xscm.moduleutil.databinding.FragmentRechargeDialogBinding;
import com.xscm.moduleutil.presenter.RechargeDialogContacts;
import com.xscm.moduleutil.presenter.RechargeDialogPresenter;
import com.xscm.moduleutil.utils.ARouteConstants;
import com.xscm.moduleutil.utils.ColorManager;
import com.xscm.moduleutil.utils.SpUtil;
import com.xscm.moduleutil.widget.PaymentUtil;
@@ -108,7 +105,7 @@ public class RechargeDialogFragment extends BaseMvpDialogFragment<RechargeDialog
private void onClick(View view) {
if (view.getId() == R.id.tv_payment) {
if (money.equals("0")) {
money = mBinding.etCustomAmount.getText().toString().trim();
money=mBinding.etCustomAmount.getText().toString().trim();
if (TextUtils.isEmpty(money)) {
ToastUtils.showShort("请选择充值金额");
return;
@@ -119,24 +116,16 @@ public class RechargeDialogFragment extends BaseMvpDialogFragment<RechargeDialog
// return;
// }
if (!mBinding.cbPrivacy.isChecked()) {
ToastUtils.showShort("请先勾选服务条款");
return;
}
if (selectedItem == null) {
ToastUtils.showShort("请选择支付方式");
return;
}
MvpPre.appPay(SpUtil.getUserId() + "", money, coin, selectedItem.getType(), type_params, gift_bag_id);
} else if (view.getId() == R.id.tv_czxy) {//充值协议
ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=37").withString("title", "充值协议").navigation();
MvpPre.appPay(SpUtil.getUserId() + "", money, coin, selectedItem.getType(),type_params,gift_bag_id);
}
}
@Override
protected void initView() {
mBinding.tvPayment.setOnClickListener(this::onClick);
mBinding.tvCzxy.setOnClickListener(this::onClick);
mBinding.recycleView1.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
bindTypeAdapter = new PayMethodAdapter(R.layout.item_bind_type);
mBinding.recycleView1.setAdapter(bindTypeAdapter);

View File

@@ -45,13 +45,13 @@ public class GiftLotteryAdapter extends BaseQuickAdapter<GiftBean, BaseViewHolde
@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));
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 countText = "x"+item.getCount();
String fullText = baseName + countText;
SpannableStringBuilder spannable = new SpannableStringBuilder(fullText);
@@ -67,7 +67,7 @@ public class GiftLotteryAdapter extends BaseQuickAdapter<GiftBean, BaseViewHolde
giftNameTextView.setText(spannable);
}
if (nickNameTextView != null && item.getNickname() != null) {
if (nickNameTextView!=null){
nickNameTextView.setText(item.getNickname());
String nickName = "赠予";
String fullText = nickName + " " + item.getNickname();

View File

@@ -103,15 +103,15 @@ import java.util.List;
// 初始化Fragment列表
private void initFragments() {
fragmentList = new ArrayList<>();
fragmentList.add(new LotteryFragment().newInstance(roomId,1)); // 第1页抽奖榜单
fragmentList.add(new LuckyFragment().newInstance(roomId,2)); // 第1页抽奖榜单
// fragmentList.add(new LotteryFragment().newInstance(roomId,1)); // 第1页抽奖榜单
}
// 初始化ViewPager
private void initViewPager() {
titleList.add("");
// titleList.add("");
titleList.add("");
FragmentManager childFragmentManager = getChildFragmentManager();
pagerAdapter = new MyPagerAdapter(childFragmentManager, fragmentList,titleList );
mBinding.ivViewPager.setAdapter(pagerAdapter);

View File

@@ -72,8 +72,7 @@ public class XlhObtainDialog extends BaseDialog<DialogXlhObtainBinding> {
mBinding.ivAgain.setOnClickListener(v -> {
if (mListener != null) {
// mListener.onPlayAgainClick();
mListener.onCloseClick();
mListener.onPlayAgainClick();
}
dismiss();
});

View File

@@ -27,15 +27,6 @@ public enum QXRoomSeatViewType {
*/
SIGNCONTRACT(10,"签约"),
/**
* 酒吧
*/
PUB(11,"酒吧"),
/**
* 酒吧
*/
PRIVATE(12,"酒吧交友小屋"),
/**
* 小黑屋麦位
*/

View File

@@ -15,8 +15,6 @@ enum class RoomType(
DATING("交友", 1,3, 4, 8), // 1、3、4、8 均对应交友
BLACK_ROOM("小黑屋", 6),
JUKEBOX("点唱", 9),
PUB_ROOM("酒吧", 11),
PRIVATE_ROOM("酒吧交友小屋", 12),
MUTUAL_ENTERTAINMENT("互娱", 7),
SIGN_CONTRACT("签约", 10);

View File

@@ -26,7 +26,7 @@ public interface ApiServer {
@FormUrlEncoded //请求验证码
@POST(Constants.SEND_CODE)
Call<BaseModel<String>> sendCode(@Field("mobile") String mobile, @Field("event") String event);
Observable<BaseModel<Object>> sendCode(@Field("mobile") String mobile, @Field("event") String event);
@FormUrlEncoded
@POST(Constants.LOGIN)
@@ -38,17 +38,8 @@ public interface ApiServer {
@FormUrlEncoded //手机换绑
@POST(Constants.MODIFY_MOBILE)
Call<BaseModel<String>> mobileView(@Field("mobile") String mobile, @Field("new_mobile") String new_mobile, @Field("sms_code") String sms_code,@Field("new_sms_code") String new_sms_code);
Call<BaseModel<String>> mobileView(@Field("mobile") String mobile, @Field("new_mobile") String new_mobile, @Field("sms_code") String sms_code);
@FormUrlEncoded
@POST(Constants.SET_PIT_TIME)
Call<BaseModel<String>> setPitTime(@Field("room_id") String roomId, @Field("time") String time);
@GET(Constants.GET_FESTIVAL_THEME)
Call<BaseModel<FestivalThemeBean>> getFestivalThemeBean();
@GET(Constants.GET_PERSONALTY_LIST_BEAN)
Call<BaseModel<List<PersonaltyListBean>>> getPersonaltyListBean(@Query("type") String type);
@GET(Constants.GET_EMOTION)
Call<BaseModel<List<Emotion>>> upEmotion();
@@ -115,7 +106,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_LOG_LIST)
Call<BaseModel<List<RevenueBean>>> getRevenueData(@Field("last_id") int page, @Field("page_limit") String page_limit, @Field("in_out_type") String in_out_type, @Field("start_time") String start_time, @Field("end_time") String end_time, @Field("gift_type") String gift_type);
Call<BaseModel<List<RevenueBean>>> getRevenueData(@Field("page") String page, @Field("page_limit") String page_limit, @Field("in_out_type") String in_out_type, @Field("start_time") String start_time, @Field("end_time") String end_time, @Field("gift_type") String gift_type);
@FormUrlEncoded
@POST(Constants.POST_WEALTH_RANKING)
@@ -138,16 +129,6 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_INVITE)
Call<BaseModel<String>> postInvite(@Field("apply_id") String apply_id, @Field("type") String type);
@GET(Constants.GET_GROUP_INFO)
Call<BaseModel<GroupBean>> getGuildInfo(@Query("guild_id")String guild_id);
@FormUrlEncoded
@POST(Constants.POST_GROUP_INFO)
Call<BaseModel<String>> setGuildInfo(@Field("guild_id") String guild_id, @Field("name") String guild_name, @Field("notice") String guild_notice,@Field("avatar") String guild_avatar);
@GET(Constants.GET_MEMBER_LIST)
Call<BaseModel<GroupUserListBean>> memberList(@Query("page")String page, @Query("page_limit") String page_limit, @Query("guild_id") String guild_id,@Query("search") String search);
@GET(Constants.GET_TEMP_KEY)
Call<BaseModel<TempKeyBean>> getTempKey();
@@ -273,8 +254,7 @@ public interface ApiServer {
@POST(Constants.URL_LOGIN)
Call<BaseModel<List<UserBean>>> oauthLogin(@Field("login_token") String login_token);
// @GET(Constants.GET_THEME_DATA)
@GET(Constants.GET_FESTIVAL_THEME)
@GET(Constants.GET_THEME_DATA)
Call<BaseModel<ThemeBean>> getThemeData();
@FormUrlEncoded
@@ -357,15 +337,6 @@ public interface ApiServer {
@GET(Constants.GIFT_LIST)
Call<BaseModel<List<RoonGiftModel>>> getGiftList(@Query("label") int label, @Query("room_id") String room_id);
@GET(Constants.GET_CUSTOM_GIFT_LIST)
Call<BaseModel<List<RoonGiftModel>>> getCustomGiftList(@Query("user_id") String user_id);
@GET(Constants.GET_NEW_GIFT_LIST)
Call<BaseModel<List<RoonGiftModel>>> getNewGiftList(@Query("label") int label, @Query("type") String type );
@GET(Constants.SET_CUSTOM_GIFT)
Call<BaseModel<String>> setCustomGift(@Query("gift_id") String gift_id, @Query("gift_remark_name") String new_gift_name ,@Query("room_id") String room_id );
@GET(Constants.TOPIC_LIST)
//获取话题
Call<BaseModel<List<HeatedBean>>> topicList(@Query("page") String page, @Query("page_limit") String page_limit);
@@ -449,17 +420,6 @@ public interface ApiServer {
@GET(Constants.GET_MY_INFO)
Call<BaseModel<UserInfo>> getMyInfo();
@GET(Constants.GET_APP_CUSTOMER_SERVICE)
Call<BaseModel<AppCustomerBean>> appCustomerService();
@FormUrlEncoded
@POST(Constants.POST_DEL_SONG)
Call<BaseModel<String>> delSong(@Field("room_id") String room_id, @Field("did") String did);
@FormUrlEncoded
@POST(Constants.POST_SEARCH_USER)
Call<BaseModel<List<MusicSongBean>>> searchSong(@Field("room_id") String room_id, @Field("search_user") String search_user);
@FormUrlEncoded
@POST(Constants.ED_USER_INFO)
Call<BaseModel<String>> editUserInfo(@Field("nickname") String nickname, @Field("birthday") String birthday, @Field("sex") String sex, @Field("avatar") String avatar, @Field("images") String images, @Field("profile") String profile, @Field("tag_id") String tag_id);
@@ -489,17 +449,6 @@ public interface ApiServer {
@GET(Constants.GET_DECORATE)
Call<BaseModel<List<ZhuangBanShangChengBean>>> getDecorateList(@Query("type") String type);
@GET(Constants.GET_DECORATE_DETAIL)
Call<BaseModel<DecorateDetailBean>> getDecorateDetail(@Query("did") String id);
@FormUrlEncoded
@POST(Constants.POST_PAY_DECORATE)
Call<BaseModel<String>> payDecorate(@Field("did") String id, @Field("day") String day,@Field("num") String num);
@FormUrlEncoded
@POST(Constants.POST_BLACK_ROOM_LIST)
Call<BaseModel<List<BlackRoomBean>>>getBlackRoomList(@Field("room_id") String roomId);
@FormUrlEncoded
@POST(Constants.POST_GZ)
Call<BaseModel<String>> userGuanz(@Field("user_id") String userId, @Field("type") String type);
@@ -548,17 +497,11 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.JOIN_ROOM)
Call<BaseModel<RoomInfoResp>> roomGetIn(@Field("room_id") String roomId, @Field("password") String password);
@FormUrlEncoded
@POST(Constants.BEFORE_JOIN_ROOM_CHECK)
Call<BaseModel<BeforeJoinRoomCheckBean>> beforeJoinRoomCheck(@Field("room_id") String roomId);
@FormUrlEncoded
@POST(Constants.TASK_JUMP_ROOM)
Call<BaseModel<String>> taskJumpRoomId(@Field("task_id") String taskId);
@GET(Constants.GET_PIT_TIME)
Call<BaseModel<List<PitTimeRespBean>>> getPitTimeList();
@FormUrlEncoded
@POST(Constants.DELETE_ALBUM_IMAGE)
Call<BaseModel<String>> deleteAlbumImage(@Field("id") String id);
@@ -589,7 +532,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.GET_ROOM_GIFT)
Call<BaseModel<RoomGiftData>> roomGift(@Field("room_id") String room_id, @Field("gift_id") String gift_id, @Field("gift_num") String num, @Field("to_uid") String to_uid, @Field("type") String gift_type, @Field("pit_number") String pit_number, @Field("heart_id") String heat_id,@Field("gift_bag_id")String gift_bag_id);
Call<BaseModel<RoomGiftData>> roomGift(@Field("room_id") String room_id, @Field("gift_id") String gift_id, @Field("gift_num") String num, @Field("to_uid") String to_uid, @Field("type") String gift_type, @Field("pit_number") String pit_number, @Field("heart_id") String heat_id);
@FormUrlEncoded
@POST(Constants.POST_CP_GIVE_GIFT)
@@ -613,12 +556,6 @@ public interface ApiServer {
@GET(Constants.GET_WALLET)
Call<BaseModel<WalletBean>> wallet();
@GET(Constants.GET_TASKS_MESSAGE)
Call<BaseModel<TasksMessage>> getTasksMessage();
@GET(Constants.GET_REDPACKET_CONFIG)
Call<BaseModel<RedPacketConfig>> getRedpacketConfig();
@FormUrlEncoded
@POST(Constants.REDPACKET_CREATE)
Call<ResponseBody> redPacketCreate(@Field("type") int type, @Field("password") String password, @Field("coin_type") int coin_type, @Field("total_amount") String total_amount,
@@ -672,11 +609,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.APPLY_PIT)
Call<BaseModel<String>> applyPit(@Field("room_id") String room_id, @Field("pit_number") String pit_number,@Field("gift_id")String gift_id);
@FormUrlEncoded
@POST(Constants.POST_LIAO_TA)
Call<BaseModel<String>> liaoTa(@Field("room_id") String room_id, @Field("to_user_id") String user_id,@Field("type")String type);
Call<BaseModel<String>> applyPit(@Field("room_id") String room_id, @Field("pit_number") String pit_number);
@FormUrlEncoded
@POST(Constants.START_FRIEND)
@@ -696,7 +629,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_KEEP_XINTIAO)
Call<BaseModel<TasksMessage>> keepXintiao(@Field("room_id") String room_id);
Call<ResponseBody> keepXintiao(@Field("room_id") String room_id);
@FormUrlEncoded
@POST(Constants.DOWN_PIT)
@@ -746,9 +679,6 @@ public interface ApiServer {
@POST(Constants.POST_AGREE_SONG)
Call<BaseModel<String>> agreeSong(@Field("room_id") String roomId, @Field("type") String type);
@GET(Constants.GET_BLIND_BOX_STATUS)
Call<BaseModel<List<BlindBoxStatus>>> blindBoxStatus();
@FormUrlEncoded
@POST(Constants.POST_END_SONG)
Call<BaseModel<String>> endSong(@Field("room_id") String roomId);
@@ -759,7 +689,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.CHANGE_SONG)
Call<BaseModel<String>> changeSong(@Field("room_id") String roomId, @Field("now_did") String now_did,@Field("is_auto_next") String is_auto_next);
Call<BaseModel<String>> changeSong(@Field("room_id") String roomId, @Field("now_did") String now_did);
@FormUrlEncoded
@POST(Constants.POST_HOST_LIST)
@@ -873,7 +803,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_ROOM_AUCTION_JOIN)
Call<BaseModel<RoomAuction.AuctionListBean>> roomAuctionJoin(@Field("auction_id") String auction_id, @Field("user_id") String user_id, @Field("gift_id") String gift_id, @Field("num") String num, @Field("type") String type,@Field("gift_bag_id") String gift_bag_id);
Call<BaseModel<RoomAuction.AuctionListBean>> roomAuctionJoin(@Field("auction_id") String auction_id, @Field("user_id") String user_id, @Field("gift_id") String gift_id, @Field("num") String num, @Field("type") String type);
@FormUrlEncoded
@@ -938,13 +868,6 @@ public interface ApiServer {
@GET(Constants.GET_GIFT_PACK_LIST_COUNT)
Call<BaseModel<GiftPackListCount>> getGiftPackListCount();
@GET(Constants.GET_GIFT_INFO_TA)
Call<BaseModel<RoonGiftModel>> getGiftInfoTa(@Query("room_id") String roomId, @Query("to_user_id") String user_id);
@FormUrlEncoded
@POST(Constants.POST_MEETING_TA)
Call<BaseModel<String>> meetingTa(@Field("room_id") String room_id, @Field("user_id") String user_id, @Field("gift_id") String gift_id);
@FormUrlEncoded
@POST(Constants.ROOM_USER_RECONNECT)
Call<BaseModel<String>> roomUserReconnect(@Field("room_id") String room_id);

View File

@@ -1,61 +0,0 @@
package com.xscm.moduleutil.http;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.http.NetworkException;
import com.blankj.utilcode.util.ToastUtils;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Response;
/**
* 项目名称:羽声语音
* 时间2025/12/23 16:58
* 用途:网络状态检查拦截器,会在每次请求前检查网络状态。
*/
public class NetworkCheckInterceptor implements Interceptor {
private final Context context;
public NetworkCheckInterceptor(Context context) {
this.context = context.getApplicationContext(); // 使用 Application Context 避免内存泄漏
}
@Override
public Response intercept(Chain chain) throws IOException {
// 检查网络连接状态
if (!isNetworkAvailable()) {
// 如果没有网络,抛出我们自定义的异常
ToastUtils.showLong("网络连接不可用,请检查您的网络设置");
}
// 如果有网络,继续执行请求
return chain.proceed(chain.request());
}
/**
* 检查网络是否可用
* @return true if network is available, false otherwise.
*/
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
// 获取所有网络信息
NetworkInfo[] networkInfos = connectivityManager.getAllNetworkInfo();
if (networkInfos != null) {
for (NetworkInfo info : networkInfos) {
if (info.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
}

View File

@@ -91,9 +91,7 @@ public class CustomMessageParser {
if (pitObject.has("pit_number") && !pitObject.get("pit_number").isJsonNull()) {
pitInfo.setPit_number(String.valueOf(pitObject.get("pit_number").getAsInt()));
}
if (pitObject.has("is_online") && !pitObject.get("is_online").isJsonNull()) {
pitInfo.setIs_online(pitObject.get("is_online").getAsInt());
}
pitList.add(pitInfo);
}

View File

@@ -1,703 +0,0 @@
package com.xscm.moduleutil.listener;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener;
import com.tencent.imsdk.v2.V2TIMCallback;
import com.tencent.imsdk.v2.V2TIMConversationListener;
import com.tencent.imsdk.v2.V2TIMGroupListener;
import com.tencent.imsdk.v2.V2TIMGroupMemberInfo;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMMessage;
import com.tencent.imsdk.v2.V2TIMSendCallback;
import com.tencent.imsdk.v2.V2TIMSimpleMsgListener;
import com.tencent.imsdk.v2.V2TIMUserInfo;
import com.xscm.moduleutil.base.CommonAppContext;
import com.xscm.moduleutil.bean.HeadlineBean;
import com.xscm.moduleutil.bean.RoomMessageEvent;
import com.xscm.moduleutil.event.UnreadCountEvent;
import com.xscm.moduleutil.http.RetrofitClient;
import com.xscm.moduleutil.utils.CustomMsgCode;
import com.xscm.moduleutil.utils.SpUtil;
import org.greenrobot.eventbus.EventBus;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
/**
* @author qx
* @data 2025/6/17
* @description: 接收消息
*/
public class MessageExListenerSingleton {
private static boolean isInitialized = false;
private static MessageExListenerSingleton instance;
private List<OnMessageReceivedListener> listeners = new ArrayList<>();
private V2TIMSimpleMsgListener simpleMsgListener;
private V2TIMAdvancedMsgListener v2TIMAdvancedMsgListener;
private static String mRoomId = "";
public static String groupId;
private V2TIMGroupListener groupListener;
private V2TIMConversationListener conversationListener; // 需要保存引用
// 添加操作状态标记
private volatile boolean isGroupOperationInProgress = false;
private final Object groupOperationLock = new Object();
private Handler mainHandler = new Handler(Looper.getMainLooper());
// 添加消息缓存机制
private static final int MAX_CACHED_MESSAGES = 20;
private final Map<String, List<RoomMessageEvent>> cachedMessages = new ConcurrentHashMap<>();
private final Set<String> joinedRooms = ConcurrentHashMap.newKeySet();
private OnMsgTaskListener onMsgTaskListener;
// private boolean listenersAdded = false; // 标记监听器是否已添加
// 1. 添加新的监听器接口
public interface PublicScreenMessageListener {
void onPublicScreenMessageReceived(RoomMessageEvent message);
}
private List<PublicScreenMessageListener> publicScreenListeners = new ArrayList<>();
// 添加监听器 // 替换原有的 addPublicScreenMessageListener 方法
public void addPublicScreenMessageListener(PublicScreenMessageListener listener) {
if (listener == null) {
return;
}
synchronized (publicScreenListeners) {
if (!publicScreenListeners.contains(listener)) {
try {
publicScreenListeners.add(listener);
} catch (Exception e) {
LogUtils.e("MessageListener", "添加 PublicScreenMessageListener 失败: " + e.getMessage());
}
}
}
}
// 同时修改 removePublicScreenMessageListener 方法
public void removePublicScreenMessageListener(PublicScreenMessageListener listener) {
if (listener == null) {
return;
}
synchronized (publicScreenListeners) {
try {
publicScreenListeners.remove(listener);
} catch (Exception e) {
LogUtils.e("MessageListener", "移除 PublicScreenMessageListener 失败: " + e.getMessage());
}
}
}
// 修改 notify 方法以增加保护
private void notifyPublicScreenListeners(RoomMessageEvent message) {
synchronized (publicScreenListeners) {
// 创建副本以避免并发修改异常
List<PublicScreenMessageListener> listenersCopy = new ArrayList<>(publicScreenListeners);
for (PublicScreenMessageListener listener : listenersCopy) {
try {
listener.onPublicScreenMessageReceived(message);
} catch (Exception e) {
LogUtils.e("MessageListener", "通知 PublicScreenMessageListener 失败: " + e.getMessage());
}
}
}
}
private MessageExListenerSingleton() {
if (!isInitialized) {
isInitialized = true;
}
}
public static MessageExListenerSingleton getInstance() {
synchronized (MessageExListenerSingleton.class) {
if (instance == null) {
instance = new MessageExListenerSingleton();
}
return instance;
}
}
/**
* 缓存消息用于在Fragment未准备好时存储消息
*/
private void cacheMessage(String roomId, RoomMessageEvent message) {
if (TextUtils.isEmpty(roomId) || message == null) {
return;
}
// 标记该房间有待处理的消息
List<RoomMessageEvent> roomMessages = cachedMessages.computeIfAbsent(roomId, k -> new ArrayList<>());
// 限制每个房间的缓存消息数量
if (roomMessages.size() >= MAX_CACHED_MESSAGES) {
roomMessages.remove(0); // 移除最旧的消息
}
roomMessages.add(message);
LogUtils.d("MessageListener", "缓存消息: roomId=" + roomId + ", msgType=" + message.getMsgType());
}
/**
* 获取并清除指定房间的缓存消息
*/
public List<RoomMessageEvent> getAndClearCachedMessages(String roomId) {
if (TextUtils.isEmpty(roomId)) {
return new ArrayList<>();
}
List<RoomMessageEvent> messages = cachedMessages.remove(roomId);
if (messages == null) {
messages = new ArrayList<>();
}
LogUtils.d("MessageListener", "获取并清除缓存消息: roomId=" + roomId + ", count=" + messages.size());
return messages;
}
/**
* 标记房间已加入
*/
public void markRoomJoined(String roomId) {
if (!TextUtils.isEmpty(roomId)) {
joinedRooms.add(roomId);
LogUtils.d("MessageListener", "标记房间已加入: " + roomId);
}
}
/**
* 检查房间是否已加入
*/
public boolean isRoomJoined(String roomId) {
return !TextUtils.isEmpty(roomId) && joinedRooms.contains(roomId);
}
/**
* 清除房间加入标记
*/
public void clearRoomJoined(String roomId) {
if (!TextUtils.isEmpty(roomId)) {
joinedRooms.remove(roomId);
LogUtils.d("MessageListener", "清除房间加入标记: " + roomId);
}
}
// 修改 joinGroup 方法,确保先退出再加入
public void joinGroup(String roomId) {
if (TextUtils.isEmpty(roomId)) {
return;
}
synchronized (groupOperationLock) {
if (isGroupOperationInProgress) {
// 如果有操作正在进行,延迟执行
mainHandler.removeCallbacksAndMessages(null);
mainHandler.postDelayed(() -> joinGroup(roomId), 100);
return;
}
isGroupOperationInProgress = true;
}
mRoomId = roomId;
new Thread(() -> {
try {
// 先退出当前群组(如果需要)
if (groupId != null && !groupId.equals(roomId)) {
LogUtils.d("MessageListener", "开始退出群组: " + groupId + "____room:" + roomId);
CountDownLatch quitLatch = new CountDownLatch(1);
boolean[] quitSuccess = {false};
try {
V2TIMManager.getInstance().quitGroup("room" + groupId, new V2TIMCallback() {
@Override
public void onSuccess() {
LogUtils.d("MessageListener", "退出群组成功: " + groupId + "____room:" + roomId);
quitSuccess[0] = true;
quitLatch.countDown();
}
@Override
public void onError(int code, String desc) {
LogUtils.e("MessageListener", "退出群组失败: " + groupId + "____room:" + roomId + ", code=" + code + ", desc=" + desc);
quitSuccess[0] = false;
quitLatch.countDown();
}
});
// 等待退出操作完成最多等待3秒
try {
quitLatch.await(3, java.util.concurrent.TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} catch (Exception e) {
LogUtils.e("MessageListener", "退出群组异常: " + e.getMessage());
}
}
// 加入新群组
LogUtils.d("MessageListener", "开始加入群组: " + roomId);
CountDownLatch joinLatch = new CountDownLatch(1);
boolean[] joinSuccess = {false};
try {
// 确保监听器已添加
ensureListenersAdded();
V2TIMManager.getInstance().joinGroup("room" + roomId, "申请加入", new V2TIMCallback() {
@Override
public void onSuccess() {
LogUtils.d("MessageListener", "加入im群组成功: " + roomId);
joinSuccess[0] = true;
groupId = roomId;
joinLatch.countDown();
// 标记房间已加入
markRoomJoined(roomId);
}
@Override
public void onError(int code, String desc) {
LogUtils.e("MessageListener", "加入群组失败: " + roomId + ", code=" + code + ", desc=" + desc);
joinSuccess[0] = false;
joinLatch.countDown();
}
});
// 等待加入操作完成最多等待3秒
try {
joinLatch.await(3, java.util.concurrent.TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} catch (Exception e) {
LogUtils.e("MessageListener", "加入群组异常: " + e.getMessage());
}
LogUtils.d("MessageListener", "群组操作完成 - 退出成功: " + (groupId == null || !groupId.equals(roomId)) + ", 加入成功: " + joinSuccess[0]);
} finally {
synchronized (groupOperationLock) {
isGroupOperationInProgress = false;
}
}
}).start();
}
private void initListeners() {
// 简单消息监听器
if (simpleMsgListener == null) {
simpleMsgListener = new V2TIMSimpleMsgListener() {
@Override
public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {
LogUtils.d("C2C 文本消息 " + sender.getNickName());
}
@Override
public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {
LogUtils.d("C2C 自定义(信令)消息 " + sender.getNickName());
String message = new String(customData, StandardCharsets.UTF_8);
RoomMessageEvent event = GsonUtils.fromJson(message, RoomMessageEvent.class);
if (event.getMsgType() == 130 || event.getMsgType() == 131) {
// EventBus.getDefault().post(event);
RetrofitClient.getInstance().getCpListener().onReceiveMsg(event);
} else if (event.getMsgType() == CustomMsgCode.INSTANCE.getCODE_TASK_APPRENTICE_JOIN_ROOM()) {
if (onMsgTaskListener != null) {
onMsgTaskListener.onMsgTask(event);
}
} else {
notifyMessageReceived(event);
}
}
@Override
public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {
LogUtils.d("群文本消息:群组 " + groupID + "" + sender.getNickName());
}
@Override
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
LogUtils.d("收到群自定义消息:群组 " + groupID + "" + sender.getNickName() +",mRoomId:"+mRoomId);
if (!groupID.equals("")) {
if (groupID.replace("room","").equals(mRoomId)) {
String message = new String(customData, StandardCharsets.UTF_8);
RoomMessageEvent event = GsonUtils.fromJson(message, RoomMessageEvent.class);
notifyMessageReceived(event);
LogUtils.d("收到群自定义消息(信令):", message);
}
} else {
String message = new String(customData, StandardCharsets.UTF_8);
LogUtils.d("收到群自定义消息(信令):", message);
HeadlineBean event = GsonUtils.fromJson(message, HeadlineBean.class);
EventBus.getDefault().post(event);
}
}
};
}
// 高级消息监听器
if (v2TIMAdvancedMsgListener == null) {
v2TIMAdvancedMsgListener = new V2TIMAdvancedMsgListener() {
@Override
public void onRecvNewMessage(V2TIMMessage msg) {
super.onRecvNewMessage(msg);
if (msg.isBroadcastMessage()) {
// 收到了广播消息
String message = new String(msg.getCustomElem().getData(), StandardCharsets.UTF_8);
LogUtils.e("收到广播消息(系统):", message);
}
}
};
}
// 群组监听器
if (groupListener == null) {
groupListener = new V2TIMGroupListener() {
@Override
public void onMemberEnter(String groupID, List<V2TIMGroupMemberInfo> memberList) {
// 有新成员加入群,该群所有的成员都能收到
}
@Override
public void onMemberLeave(String groupID, V2TIMGroupMemberInfo member) {
// 有成员离开群,该群所有的成员都能收到
}
@Override
public void onReceiveRESTCustomData(String groupID, byte[] customData) {
String message = "";
try {
LogUtils.e("收到群自定义消息",groupID);
message = new String(customData, StandardCharsets.UTF_8);
LogUtils.e("收到群自定义消息(系统)" + message);
} catch (Exception e) {
// 处理转换过程中可能出现的异常,例如记录日志
LogUtils.e("转换 customData 为 String 时出错:" + e.getMessage());
return; // 退出方法,避免后续代码执行
}
RoomMessageEvent event = null;
try {
// 特殊处理某些消息类型
event = parseSpecialMessageTypes(message);
if (event == null) {
// 使用默认解析
event = GsonUtils.fromJson(message, RoomMessageEvent.class);
}
LogUtils.e("收到群自定义消息:" + mRoomId + "===" + event);
// event = GsonUtils.fromJson(message, RoomMessageEvent.class);
} catch (Exception e) {
// 处理 JSON 解析过程中可能出现的异常,例如记录日志
LogUtils.e("解析 JSON 数据时出错:" + e.getMessage());
return; // 退出方法,避免后续代码执行
}
if (groupID.contains(mRoomId)) {
notifyMessageReceived(event);
}
}
};
}
// 会话监听器
if (conversationListener == null) {
conversationListener = new V2TIMConversationListener() {
@Override
public void onTotalUnreadMessageCountChanged(long totalUnreadCount) {
super.onTotalUnreadMessageCountChanged(totalUnreadCount);
UnreadCountEvent event = CommonAppContext.getInstance().getUnreadCountEvent();
if (event == null) {
event = new UnreadCountEvent();
event.setBLong(0);
}
event.setALong(totalUnreadCount);
CommonAppContext.getInstance().setUnreadCountEvent(event);
EventBus.getDefault().post(event);
}
};
}
}
// 添加所有监听器
private void addAllListeners() {
if (simpleMsgListener != null) {
V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
}
if (v2TIMAdvancedMsgListener != null) {
V2TIMManager.getMessageManager().addAdvancedMsgListener(v2TIMAdvancedMsgListener);
}
if (groupListener != null) {
V2TIMManager.getInstance().addGroupListener(groupListener);
}
if (conversationListener != null) {
V2TIMManager.getConversationManager().addConversationListener(conversationListener);
}
}
// 移除所有监听器
private static void removeAllListeners() {
if (instance != null) {
if (instance.simpleMsgListener != null) {
V2TIMManager.getInstance().removeSimpleMsgListener(instance.simpleMsgListener);
}
if (instance.v2TIMAdvancedMsgListener != null) {
V2TIMManager.getMessageManager().removeAdvancedMsgListener(instance.v2TIMAdvancedMsgListener);
}
if (instance.groupListener != null) {
V2TIMManager.getInstance().removeGroupListener(instance.groupListener);
}
if (instance.conversationListener != null) {
V2TIMManager.getConversationManager().removeConversationListener(instance.conversationListener);
}
// instance.listenersAdded = false; // 重置标记
}
}
// 修改 quitGroup 方法
public static void quitGroup(String mRoomId) {
V2TIMManager.getInstance().quitGroup("room" + mRoomId, new V2TIMCallback() {
@Override
public void onSuccess() {
LogUtils.d("@@@", "退出群组成功" + mRoomId);
// removeAllListeners(); // 移除所有监听器
}
@Override
public void onError(int code, String desc) {
LogUtils.d("@@@", "退出群组失败" + mRoomId, code, desc);
// removeAllListeners(); // 即使失败也移除监听器
}
});
if (instance != null) {
instance.listeners.clear();
// removeAllListeners();
isInitialized = false;
groupId = null;
LogUtils.e("@@@", "重置成功");
}
}
// 修改 reset 方法
public static void reset(String roomId) {
if (instance != null) {
instance.listeners.clear();
// removeAllListeners();
isInitialized = false;
groupId = null;
// instance = null;
quitGroup(roomId);
LogUtils.e("@@@", "重置成功");
}
}
// 确保监听器已添加
public void ensureListenersAdded() {
initListeners();
addAllListeners();
}
private RoomMessageEvent parseSpecialMessageTypes(String message) {
try {
JsonObject jsonObject = new JsonParser().parse(message).getAsJsonObject();
int msgType = jsonObject.get("MsgType").getAsInt();
if (msgType == 1053) {
return CustomMessageParser.parseMessageType1053(jsonObject);
} else if (msgType == 1054) {
return CustomMessageParser.parseMessageType1054(jsonObject);
}
return null; // 不是特殊类型,使用默认解析
} catch (Exception e) {
LogUtils.e("特殊消息解析失败: " + e.getMessage());
return null;
}
}
public void addOnMessageReceivedListener(OnMessageReceivedListener listener) {
listeners.add(listener);
}
/**
* 移除群组相关的监听器
*/
private static void removeGroupListeners() {
if (instance != null) {
// 移除消息监听器
if (instance.simpleMsgListener != null) {
V2TIMManager.getInstance().removeSimpleMsgListener(instance.simpleMsgListener);
}
if (instance.v2TIMAdvancedMsgListener != null) {
V2TIMManager.getMessageManager().removeAdvancedMsgListener(instance.v2TIMAdvancedMsgListener);
}
// 移除群组监听器
if (instance.groupListener != null) {
V2TIMManager.getInstance().removeGroupListener(instance.groupListener);
}
}
}
public void sendCustomRoomMessage(String roomId, byte[] binaryData) {
// 创建自定义群消息
V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createCustomMessage(binaryData);
// v2TIMMessage.setNeedReadReceipt(true);
// 发送消息
V2TIMManager.getMessageManager().sendMessage(
v2TIMMessage,
null,
"room" + roomId,
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
false,
null,
sendCallback
);
}
// TODO: 2025/11/19 添加发送公共方法messageType发送的typemessage发送的内容 userId发送给谁
public void sendCustomC2CMessage(int messageType, String message, String userId) {
RoomMessageEvent.T t = new RoomMessageEvent.T();
t.setFromUserInfo(SpUtil.getUserInfo());
t.setText(message);
RoomMessageEvent roomMessageEvent = new RoomMessageEvent(messageType, mRoomId, t);
String json = GsonUtils.toJson(roomMessageEvent);
// 转换为 byte[]
byte[] binaryData = json.getBytes(StandardCharsets.UTF_8);
// 创建自定义群消息
V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createCustomMessage(binaryData);
v2TIMMessage.setExcludedFromUnreadCount(true);
v2TIMMessage.setExcludedFromContentModeration(true);
// v2TIMMessage.setNeedReadReceipt(true);
//
// // 发送消息
V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, "u" + userId, null, V2TIMMessage.V2TIM_PRIORITY_HIGH,
true,
null,
sendCallback);
}
// TODO: 2025/11/19 添加发送公共方法messageType发送的typemessage发送的内容 userId发送给谁
public void sendCustomC2CMessage(int messageType, String userId,RoomMessageEvent.T text) {
text.setFromUserInfo(SpUtil.getUserInfo());
LogUtils.e("发送消息", "messageType:" + messageType + "\nuserId:" + userId + "\ntext:" + text,toString());
RoomMessageEvent roomMessageEvent = new RoomMessageEvent(messageType, mRoomId, text);
String json = GsonUtils.toJson(roomMessageEvent);
// 转换为 byte[]
byte[] binaryData = json.getBytes(StandardCharsets.UTF_8);
// 创建自定义群消息
V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createCustomMessage(binaryData);
v2TIMMessage.setExcludedFromUnreadCount(true);
v2TIMMessage.setExcludedFromContentModeration(true);
// v2TIMMessage.setNeedReadReceipt(true);
//
// // 发送消息
V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, "u" + userId, null, V2TIMMessage.V2TIM_PRIORITY_HIGH,
true,
null,
sendCallback);
}
public void sendCustomC2CMessage125(String userId, byte[] binaryData) {
// 创建自定义群消息
V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createCustomMessage(binaryData);
v2TIMMessage.setExcludedFromUnreadCount(true);
v2TIMMessage.setExcludedFromContentModeration(true);
// v2TIMMessage.setNeedReadReceipt(true);
//
// // 发送消息
V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, "u" + userId, null, V2TIMMessage.V2TIM_PRIORITY_HIGH,
true,
null,
sendCallback);
}
// RoomFragment.java 中添加
private final V2TIMSendCallback<V2TIMMessage> sendCallback = new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onProgress(int progress) {
// 可选实现
}
@Override
public void onSuccess(V2TIMMessage message) {
Log.d("MessageSender", "发送成功");
}
@Override
public void onError(int code, String desc) {
Log.e("MessageSender", "发送失败: code=" + code + ", desc=" + desc);
}
};
private void notifyMessageReceived(RoomMessageEvent message) {
// for (OnMessageReceivedListener listener : listeners) {
// listener.onMessageReceived(message);
// }
if ((message.getMsgType() == 1001 || message.getMsgType() == 1080) && publicScreenListeners.isEmpty()) {
cacheMessage(message.getRoomId(), message);
}
// 通知原有的监听器
for (OnMessageReceivedListener listener : listeners) {
listener.onMessageReceived(message);
}
// 通知 PublicScreenEaseChatFragment 监听器
for (PublicScreenMessageListener listener : publicScreenListeners) {
listener.onPublicScreenMessageReceived(message);
}
}
public interface OnMessageReceivedListener {
void onMessageReceived(RoomMessageEvent message);
}
public void setOnMsgTaskListener(OnMsgTaskListener listener) {
this.onMsgTaskListener = listener;
}
public interface OnMsgTaskListener {
void onMsgTask(RoomMessageEvent message);
}
}

View File

@@ -41,8 +41,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import lombok.Getter;
/**
* @author qx
* @data 2025/6/17
@@ -54,8 +52,7 @@ public class MessageListenerSingleton {
private List<OnMessageReceivedListener> listeners = new ArrayList<>();
private V2TIMSimpleMsgListener simpleMsgListener;
private V2TIMAdvancedMsgListener v2TIMAdvancedMsgListener;
@Getter
public String mRoomId = "";
private static String mRoomId = "";
public static String groupId;
private V2TIMGroupListener groupListener;
private V2TIMConversationListener conversationListener; // 需要保存引用
@@ -99,6 +96,7 @@ public class MessageListenerSingleton {
// 同时修改 removePublicScreenMessageListener 方法
public void removePublicScreenMessageListener(PublicScreenMessageListener listener) {
mRoomId = "";
if (listener == null) {
return;
}
@@ -207,16 +205,16 @@ public class MessageListenerSingleton {
// 修改 joinGroup 方法,确保先退出再加入
public void joinGroup(String roomId) {
if (TextUtils.isEmpty(roomId)) {
return;
}
if (Objects.equals(mRoomId, roomId))
return;
synchronized (groupOperationLock) {
if (isGroupOperationInProgress) {
// 如果有操作正在进行,延迟执行
mainHandler.removeCallbacksAndMessages(null);
mainHandler.postDelayed(() -> joinGroup(roomId), 200);
mainHandler.postDelayed(() -> joinGroup(roomId), 100);
return;
}
@@ -342,14 +340,12 @@ public class MessageListenerSingleton {
@Override
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
LogUtils.d("收到群自定义消息:群组 " + groupID + "" + sender.getNickName() +",mRoomId:"+mRoomId);
LogUtils.d("收到群自定义消息:群组 " + groupID + "" + sender.getNickName());
if (!groupID.equals("")) {
if (groupID.replace("room","").equals(mRoomId)) {
String message = new String(customData, StandardCharsets.UTF_8);
RoomMessageEvent event = GsonUtils.fromJson(message, RoomMessageEvent.class);
notifyMessageReceived(event);
LogUtils.d("收到群自定义消息(信令):", message);
}
String message = new String(customData, StandardCharsets.UTF_8);
RoomMessageEvent event = GsonUtils.fromJson(message, RoomMessageEvent.class);
notifyMessageReceived(event);
LogUtils.d("收到群自定义消息(信令):", message);
} else {
String message = new String(customData, StandardCharsets.UTF_8);
LogUtils.d("收到群自定义消息(信令):", message);

View File

@@ -58,11 +58,21 @@ public abstract class BasePresenter<V extends IView> implements IPresenter {
@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;
}

View File

@@ -43,7 +43,7 @@ public class RewardGiftContacts {
void giveGift(String user_id, String gid, String num, String to_uid, String gift_type);
void roomGift(String room_id, String gift_id, String gift_num, String to_uid, String type, String pit_number,String heart_id,String gift_bag_id);
void roomGift(String room_id, String gift_id, String gift_num, String to_uid, String type, String pit_number,String heart_id);
void wallet();
@@ -51,7 +51,7 @@ public class RewardGiftContacts {
void setRoomApply(String room_id, String gift_id,String gift_price);
void roomAuctionJoin(String auction_id,String user_id, String gift_id, String num,String type,String gift_bag_id);
void roomAuctionJoin(String auction_id,String user_id, String gift_id, String num,String type);
void giftPack();
void getGiftPack(String roomId,String userId,String heart_id,String auction_id );

View File

@@ -103,8 +103,8 @@ public class RewardGiftPresenter extends BasePresenter<RewardGiftContacts.View>
}
@Override
public void roomGift(String room_id, String gift_id, String gift_num, String to_uid, String type, String pit_number, String heart_id,String gift_bag_id) {
RetrofitClient.getInstance().roomGift(room_id, gift_id, gift_num, to_uid, type, pit_number, heart_id,gift_bag_id, new BaseObserver<RoomGiftData>() {
public void roomGift(String room_id, String gift_id, String gift_num, String to_uid, String type, String pit_number, String heart_id) {
RetrofitClient.getInstance().roomGift(room_id, gift_id, gift_num, to_uid, type, pit_number, heart_id, new BaseObserver<RoomGiftData>() {
@Override
public void onSubscribe(Disposable d) {
@@ -177,8 +177,8 @@ public class RewardGiftPresenter extends BasePresenter<RewardGiftContacts.View>
}
@Override
public void roomAuctionJoin(String auction_id, String user_id, String gift_id, String num, String type,String gift_bg) {
RetrofitClient.getInstance().roomAuctionJoin(auction_id, user_id, gift_id, num, type,gift_bg, new BaseObserver<RoomAuction.AuctionListBean>() {
public void roomAuctionJoin(String auction_id, String user_id, String gift_id, String num, String type) {
RetrofitClient.getInstance().roomAuctionJoin(auction_id, user_id, gift_id, num, type, new BaseObserver<RoomAuction.AuctionListBean>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
@@ -208,6 +208,9 @@ public class RewardGiftPresenter extends BasePresenter<RewardGiftContacts.View>
if (MvpRef == null) {
MvpRef = new WeakReference<>(mView);
}
if (giftPackBeans == null) {
return;
}
MvpRef.get().giftPack(giftPackBeans);
}
});

View File

@@ -18,8 +18,6 @@ import android.content.Context;
import android.media.projection.MediaProjection;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
@@ -56,9 +54,7 @@ import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -107,7 +103,7 @@ public class AgoraManager {
private static List<Music> musicList;
private static boolean isBjMusic = false;
private List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private static List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private static ChannelMediaOptions options;
private static RtcConnection connection;
private String pkRoomId = "";
@@ -124,12 +120,6 @@ public class AgoraManager {
private Disposable disposableB;
private Disposable disposableC;
// UI 刷新最小间隔ms
private static final long SOUND_UI_INTERVAL = 50;
private final Handler uiHandler = new Handler(Looper.getMainLooper());
private long lastDispatchTime = 0;
public void setLastRoomId(String value) {
lastRoomId = value;
}
@@ -197,7 +187,7 @@ public class AgoraManager {
config.mAppId = appId;
config.mEventHandler = getDefaultEventHandler();
config.mChannelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
config.mAudioScenario = Constants.AUDIO_SCENARIO_GAME_STREAMING;
config.mAudioScenario = Constants.AUDIO_SCENARIO_CHORUS;
config.mAreaCode = 1;
rtcEngine = (RtcEngineEx) RtcEngine.create(config);
@@ -210,7 +200,7 @@ public class AgoraManager {
try {
rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO,
Constants.AUDIO_SCENARIO_GAME_STREAMING);
rtcEngine.enableAudioVolumeIndication(500, 3, true);
rtcEngine.enableAudioVolumeIndication(200, 3, true);
rtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
rtcEngine.muteLocalAudioStream(true); // 默认静音
rtcEngine.muteAllRemoteAudioStreams(false); // 监听远端的音频
@@ -406,14 +396,14 @@ public class AgoraManager {
@Override
public void onAudioEffectFinished(int soundId) {
super.onAudioEffectFinished(soundId);
// LogUtils.e("onAudioEffectFinished", "soundId------>" + soundId);
LogUtils.e("onAudioEffectFinished", "soundId------>" + soundId);
}
@Override
public void onRemoteAudioStateChanged(int uid, int state, int reason, int elapsed) {
super.onRemoteAudioStateChanged(uid, state, reason, elapsed);
if (state == 0){
// LogUtils.e("onRemoteAudioStateChanged", "uid------>" + uid, "state------>" + state, "reason------>" + reason, "elapsed------>" + elapsed);
LogUtils.e("onRemoteAudioStateChanged", "uid------>" + uid, "state------>" + state, "reason------>" + reason, "elapsed------>" + elapsed);
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
// Pk 关闭远端推流
@@ -426,7 +416,7 @@ public class AgoraManager {
@Override
public void onUserMuteAudio(int uid, boolean muted) {
super.onUserMuteAudio(uid, muted);
// LogUtils.e("onUserMuteAudio", "uid------>" + uid, "muted------>" + muted);
LogUtils.e("onUserMuteAudio", "uid------>" + uid, "muted------>" + muted);
}
@Override
@@ -559,34 +549,22 @@ public class AgoraManager {
if (speakers == null || speakers.length == 0) return;
// 1⃣ 构建局部 Map声网线程私有
Map<String, Integer> localMap = new HashMap<>();
for (AudioVolumeInfo info : speakers) {
String userId = (info.uid == 0)
? SpUtil.getUserId()+""
: String.valueOf(info.uid);
localMap.put(userId, info.volume);
}
// long now = SystemClock.uptimeMillis();
// if (now - lastDispatchTime < SOUND_UI_INTERVAL) return;
// lastDispatchTime = now;
// 2⃣ 只把“不可变快照”丢给 UI
uiHandler.post(() -> dispatchVolume(localMap));
}
private void dispatchVolume(Map<String, Integer> volumeSnapshot) {
if (soundLevelUpdateListeners.isEmpty()) return;
for (Map.Entry<String, Integer> entry : volumeSnapshot.entrySet()) {
for (final AudioVolumeInfo info : speakers) {
final int uid = info.uid;
final int volume = info.volume;
// 回调所有监听器
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
listener.onRemoteSoundLevelUpdate(entry.getKey(), entry.getValue());
ThreadUtils.runOnUiThread(() -> {
// 远程用户音量变化
listener.onRemoteSoundLevelUpdate(uid > 0 ? String.valueOf(uid) : SpUtil.getUserId() + "", volume);
});
}
}
}
}
@Override
public void onLocalVideoStateChanged(Constants.VideoSourceType source, int state, int reason) {
super.onLocalVideoStateChanged(source, state, reason);
@@ -708,37 +686,37 @@ public class AgoraManager {
@Override
public void onPlayerEvent(io.agora.mediaplayer.Constants.MediaPlayerEvent eventCode, long elapsedTime, String message) {
// LogUtils.e("@@@", "eventCode: " + eventCode + ", elapsedTime: " + elapsedTime + ", message: " + message);
LogUtils.e("@@@", "eventCode: " + eventCode + ", elapsedTime: " + elapsedTime + ", message: " + message);
}
@Override
public void onMetaData(io.agora.mediaplayer.Constants.MediaPlayerMetadataType type, byte[] data) {
// LogUtils.e("@@@", "type: " + type + ", data: " + data);
LogUtils.e("@@@", "type: " + type + ", data: " + data);
}
@Override
public void onPlayBufferUpdated(long playCachedBuffer) {
// LogUtils.e("@@@", "playCachedBuffer: " + playCachedBuffer);
LogUtils.e("@@@", "playCachedBuffer: " + playCachedBuffer);
}
@Override
public void onPreloadEvent(String src, io.agora.mediaplayer.Constants.MediaPlayerPreloadEvent event) {
// LogUtils.e("@@@", "src: " + src + ", event: " + event);
LogUtils.e("@@@", "src: " + src + ", event: " + event);
}
@Override
public void onAgoraCDNTokenWillExpire() {
// LogUtils.e("@@@", "onAgoraCDNTokenWillExpire");
LogUtils.e("@@@", "onAgoraCDNTokenWillExpire");
}
@Override
public void onPlayerSrcInfoChanged(SrcInfo from, SrcInfo to) {
// LogUtils.e("@@@", "from: " + from + ", to: " + to);
LogUtils.e("@@@", "from: " + from + ", to: " + to);
}
@Override
public void onPlayerInfoUpdated(PlayerUpdatedInfo info) {
// LogUtils.e("@@@", "info: " + info);
LogUtils.e("@@@", "info: " + info);
}
@Override
@@ -1011,7 +989,6 @@ public class AgoraManager {
// }
// }
public void addSoundLevelListener(SoundLevelUpdateListener listener) {
LogUtils.e("AgoraManager", "addSoundLevelListener: " + listener +"============"+soundLevelUpdateListeners.size());
if (soundLevelUpdateListeners != null) {
soundLevelUpdateListeners.add(listener);
}
@@ -1023,24 +1000,10 @@ public class AgoraManager {
}
}
public void removeSoundLevelListenerAll() {
if (soundLevelUpdateListeners != null)
soundLevelUpdateListeners.clear();
}
/**
* This method searches for music based on a given keyword and page number.
* It initializes the music content center if it's not already created.
*
* @param keyword The keyword to search for music
* @param page The page number of the search results
*/
public void searchMusic(String keyword, int page) {
// Check if musicContentCenter is initialized, if not create it
if (musicContentCenter == null) {
musicContentCenter = IAgoraMusicContentCenter.create(rtcEngine);
}
// Perform the music search with the keyword, page number and page size (20)
musicContentCenter.searchMusic(keyword, page, 20);
}
@@ -1380,12 +1343,12 @@ public class AgoraManager {
@Override
public void connected(@NonNull DownloadTask task, int blockCount, long currentOffset, long totalLength) {
// com.xscm.moduleutil.utils.logger.Logger.e("connected", blockCount);
com.xscm.moduleutil.utils.logger.Logger.e("connected", blockCount);
}
@Override
public void progress(@NonNull DownloadTask task, long currentOffset, long totalLength) {
// com.xscm.moduleutil.utils.logger.Logger.e("progress", currentOffset);
com.xscm.moduleutil.utils.logger.Logger.e("progress", currentOffset);
}
@Override

View File

@@ -139,8 +139,8 @@ public class MqttConnect {
public void close() {
if (mqttClient != null && mqttClient.isConnected()) {
try {
mqttClient.disconnect();
mqttClient.close();
mqttClient.disconnect();
mqttClient = null;
} catch (MqttException e) {
LogUtils.e(Tag, "关闭MQTT连接报错" + e.getMessage());

View File

@@ -16,7 +16,7 @@ import java.util.List;
*/
public class BackgroundManager {
private static BackgroundManager instance;
private int backgroundUrl;
private String backgroundUrl;
private Drawable backgroundDrawable;
private List<BackgroundUpdateListener> listeners = new ArrayList<>();
@@ -31,16 +31,12 @@ public class BackgroundManager {
return instance;
}
public void setBackgroundUrl(int url) {
public void setBackgroundUrl(String url) {
this.backgroundUrl = url;
// loadBackground();
loadBackground();
}
// public void setBackgroundUrl(String url) {
// this.backgroundUrl = url;
// loadBackground();
// }
public int getBackgroundUrl() {
public String getBackgroundUrl() {
return backgroundUrl;
}
@@ -48,42 +44,43 @@ public class BackgroundManager {
return backgroundDrawable;
}
// private void loadBackground() {
// if (backgroundUrl == null || backgroundUrl.isEmpty()) {
// return;
// }
// }
private void loadBackground() {
if (backgroundUrl == null || backgroundUrl.isEmpty()) {
return;
}
// 这里使用一个临时的 ImageView 来加载图片
// 实际项目中可能需要使用 Application Context
// 为简化,这里直接加载到 drawable
}
public void loadBackgroundDrawable(android.content.Context context, BackgroundLoadCallback callback) {
if (backgroundUrl == 0 ) {
if (backgroundUrl == null || backgroundUrl.isEmpty()) {
callback.onLoadFailed();
return;
}
callback.onLoadComplete(backgroundUrl);
Glide.with(context)
.asDrawable()
.load(backgroundUrl)
.into(new CustomTarget<Drawable>() {
@Override
public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
backgroundDrawable = resource;
callback.onLoadSuccess(resource);
notifyBackgroundUpdated(resource);
}
// Glide.with(context)
// .asDrawable()
// .load(backgroundUrl)
// .into(new CustomTarget<Drawable>() {
// @Override
// public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
// backgroundDrawable = resource;
// callback.onLoadSuccess(resource);
// notifyBackgroundUpdated(resource);
// }
//
// @Override
// public void onLoadCleared(Drawable placeholder) {
// callback.onLoadFailed();
// }
//
// @Override
// public void onLoadFailed(Drawable errorDrawable) {
// super.onLoadFailed(errorDrawable);
// callback.onLoadFailed();
// }
// });
@Override
public void onLoadCleared(Drawable placeholder) {
callback.onLoadFailed();
}
@Override
public void onLoadFailed(Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
callback.onLoadFailed();
}
});
}
public void addListener(BackgroundUpdateListener listener) {
@@ -105,8 +102,6 @@ public class BackgroundManager {
public interface BackgroundLoadCallback {
void onLoadSuccess(Drawable drawable);
void onLoadFailed();
void onLoadComplete(int resultId);
}
public interface BackgroundUpdateListener {

View File

@@ -5,6 +5,4 @@ object CustomMsgCode {
val CODE_TASK_APPRENTICE_JOIN_ROOM = 132
val CODE_TASK_APPRENTICE_JOIN_ROOM_MSG = "您的师傅邀请您进入房间,您是否同意?"
val CODE_TASK_APPRENTICE_JOIN_ROOM_MSG_REFUSE = "您的徒弟拒绝了您的邀请。"
val CODE_USER_SIGN_IN = "签到"
}

View File

@@ -9,6 +9,7 @@ import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.Log;
import com.alibaba.android.arouter.utils.TextUtils;
import com.blankj.utilcode.util.FileUtils;
@@ -229,14 +230,14 @@ public class DownloadUtil {
}
}
if (TextUtils.isEmpty(mApkPath)) {
LogUtils.e(TAG, "downloadApk: 存储路径为空了");
Log.e(TAG, "downloadApk: 存储路径为空了");
return;
}
//建立一个文件
mFile = new File(mApkPath);
if (FileUtils.createFileByDeleteOldFile(mFile)) {
if (mApi == null) {
LogUtils.e(TAG, "downloadApk: 下载接口为空了");
Log.e(TAG, "downloadApk: 下载接口为空了");
return;
}
mCall = mApi.downloadFile(url);
@@ -283,7 +284,7 @@ public class DownloadUtil {
while ((len = is.read(buff)) != -1) {
os.write(buff, 0, len);
currentLength += len;
LogUtils.e(TAG, "当前进度: " + currentLength);
Log.e(TAG, "当前进度: " + currentLength);
long finalCurrentLength = currentLength;
HANDLER.post(new Runnable() {
@Override

View File

@@ -16,14 +16,10 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.signature.ObjectKey;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.widget.GrayscaleTransformation;
@@ -37,33 +33,25 @@ import java.security.MessageDigest;
*/
public class ImageLoader {
private static RequestOptions createUrlOnlyOptions(String url) {
String urls = String.valueOf(new GlideUrl(url));
return new RequestOptions().signature(new ObjectKey(urls)).diskCacheStrategy(DiskCacheStrategy.ALL)
.skipMemoryCache(false)
.format(DecodeFormat.PREFER_RGB_565);
// 禁止尺寸影响缓存
// .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}
public static void loadHead(Context context, ImageView view, String url) {
RequestOptions options = RequestOptions.circleCropTransform();
Glide.with(context).load(url).apply(createUrlOnlyOptions(url)).error(com.xscm.moduleutil.R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).thumbnail(0.3f).into(view);
Glide.with(context).load(url).apply(options).error(com.xscm.moduleutil.R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
}
public static void loadHead(ImageView view, String url) {
RequestOptions options = RequestOptions.circleCropTransform();
Glide.with(view).load(url).apply(createUrlOnlyOptions(url)).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).thumbnail(0.3f).into(view);
Glide.with(view).load(url).apply(options).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
}
public static void loadImage(ImageView view, String url) {
RequestOptions options = RequestOptions.circleCropTransform();
Glide.with(view).load(url).apply(createUrlOnlyOptions(url)).error(R.mipmap.default_image).placeholder(R.mipmap.default_image).thumbnail(0.3f).into(view);
Glide.with(view).load(url).error(R.mipmap.default_image).placeholder(R.mipmap.default_image).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
}
public static void loadImage(Context context, ImageView view, String url) {
Glide.with(context).load(url).apply(createUrlOnlyOptions(url)).error(R.mipmap.default_image).placeholder(R.mipmap.default_image)
.thumbnail(0.3f).into(view);
Glide.with(context).load(url).error(R.mipmap.default_image).placeholder(R.mipmap.default_image)
.diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
}
/**
* 加载图片并灰度
@@ -74,7 +62,7 @@ public class ImageLoader {
*/
public static void loadImage(Context context,ImageView view, String url, Float placeholder) {
Glide.with(context).load(url).apply(RequestOptions.bitmapTransform(new GrayscaleTransformation(placeholder)))
.error(R.mipmap.default_image).placeholder(R.mipmap.default_image).diskCacheStrategy(DiskCacheStrategy.RESOURCE).thumbnail(0.3f).into(view);
.error(R.mipmap.default_image).placeholder(R.mipmap.default_image).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
}
// 可调节灰度程度的方法
public static void loadGrayscaleImage(Context context, String url, ImageView imageView, float saturation) {
@@ -90,7 +78,7 @@ public class ImageLoader {
} else {
view.setVisibility(View.VISIBLE);
}
Glide.with(context).load(url).diskCacheStrategy(DiskCacheStrategy.RESOURCE).into(view);
Glide.with(context).load(url).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
}
}

View File

@@ -26,20 +26,13 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
import com.blankj.utilcode.util.ConvertUtils;
import com.blankj.utilcode.util.Utils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.integration.webp.decoder.WebpDrawable;
import com.bumptech.glide.integration.webp.decoder.WebpDrawableTransformation;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.resource.bitmap.CenterInside;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.RequestListener;
@@ -77,19 +70,11 @@ public class ImageUtils {
public static final int ANIM = -1;
private static RequestOptions createUrlOnlyOptions(String url) {
return new RequestOptions().signature(new ObjectKey(url!=null ? url :"")).diskCacheStrategy(DiskCacheStrategy.ALL)
.skipMemoryCache(false)
.format(DecodeFormat.PREFER_RGB_565);
// 禁止尺寸影响缓存
// .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}
/**
* 默认加载
*/
public static void loadImageView(String path, ImageView mImageView) {
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path)).thumbnail(0.3f).into(mImageView);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
@@ -97,7 +82,7 @@ public class ImageUtils {
*/
public static void loadIcon(String path, ImageView mImageView) {
mImageView.setVisibility(TextUtils.isEmpty(path) ? GONE : View.VISIBLE);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path)).thumbnail(0.3f).into(mImageView);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
@@ -116,8 +101,8 @@ public class ImageUtils {
* @param height
*/
public static void loadSample(String path, ImageView mImageView, int width, int height) {
RequestOptions options = new RequestOptions().override(width, height).diskCacheStrategy(DiskCacheStrategy.RESOURCE);
Glide.with(mImageView).load(path).apply(options).thumbnail(0.3f).into(mImageView);
RequestOptions options = new RequestOptions().override(width, height).diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(mImageView).load(path).apply(options).into(mImageView);
}
/**
@@ -151,9 +136,7 @@ public class ImageUtils {
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
}
private static Map<Integer, SVGAVideoEntity> svgaCache = new HashMap<>();
// TODO: 2025/8/22 播放svga
public static void loadDecorationAvatar2(int resourceId, SVGAImageView mImageView) {
// 从资源文件夹加载SVGA文件
@@ -172,7 +155,7 @@ public class ImageUtils {
// 没有缓存,正常加载
SVGAParser parser = SVGAParser.Companion.shareParser();
InputStream inputStream = mImageView.getContext().getResources().openRawResource(resourceId);
parser.decodeFromAssets("heart_line_31.svga", new SVGAParser.ParseCompletion() {
parser.decodeFromAssets("heart_line_31.svga", new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
if (mImageView != null) {
@@ -196,8 +179,7 @@ public class ImageUtils {
Logger.e("Resource ID is 0 or invalid");
}
}
public static void loadSetErrorImg(String path, ImageView mImageView, int errorRes) {
public static void loadSetErrorImg(String path, ImageView mImageView,int errorRes) {
if (mImageView == null) {
return;
}
@@ -209,8 +191,7 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path)).error(errorRes).
placeholder(errorRes).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).thumbnail(0.3f).into(mImageView);
Glide.with(mImageView).load(path).error(errorRes).placeholder(errorRes).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
@@ -226,8 +207,7 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path))
.placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.RESOURCE).thumbnail(0.3f).into(mImageView);
Glide.with(mImageView).load(path).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadHeadCC(String path, ImageView mImageView) {
@@ -241,9 +221,7 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).asBitmap().load(path)
.apply(createUrlOnlyOptions(path))
.error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).centerCrop().thumbnail(0.3f).into(mImageView);
Glide.with(mImageView).load(path).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadHead(String path, ImageView mImageView) {
@@ -257,8 +235,7 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path))
.thumbnail(0.3f).into(mImageView);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadHeadCC(String path, ImageView mImageView, LinearLayout.LayoutParams params) {
@@ -272,9 +249,8 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).asBitmap().load(path)
.apply(createUrlOnlyOptions(path))
.error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
Glide.with(mImageView).asBitmap().load(path).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
.diskCacheStrategy(DiskCacheStrategy.ALL)
// 添加加载监听
.listener(new RequestListener<Bitmap>() {
@Override
@@ -289,7 +265,7 @@ public class ImageUtils {
// 加载成功resource 就是最终的 Bitmap 对象
int imageWidth = resource.getWidth(); // 图片原始宽度
int imageHeight = resource.getHeight(); // 图片原始高度
// params.width = (int) (imageWidth * 1.3);
params.width = (int)(imageWidth * 1.3);
// 这里可以使用宽高(如打印、适配布局等)
Log.d("GlideImageSize", "宽度:" + imageWidth + ",高度:" + imageHeight);
return false; // 返回 falseGlide 会继续执行默认的图片设置(显示到 mImageView
@@ -307,22 +283,22 @@ public class ImageUtils {
}
public static void loadCenterCrop(String path, ImageView mImageView) {
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path)).centerCrop().into(mImageView);
Glide.with(mImageView).load(path).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadRes(int path, ImageView mImageView) {
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.RESOURCE).into(mImageView);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
* 加载图片(优先使用本地缓存,无缓存则下载)
*
* @param context 上下文
* @param url 图片 URL
* @param context 上下文
* @param url 图片 URL
* @param imageView 目标 ImageView
*/
public static void loadImageWithCache(String url, ImageView imageView) {
public static void loadImageWithCache(Context context, String url, ImageView imageView) {
if (TextUtils.isEmpty(url)) return;
// 去掉动态参数,提取稳定 URL
@@ -330,9 +306,9 @@ public class ImageUtils {
String signature = Md5Utils.getMD5String(stableUrl); // 使用 MD5 生成唯一签名
// Glide 加载配置
Glide.with(imageView)
Glide.with(context)
.load(stableUrl)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) // 缓存所有版本
.diskCacheStrategy(DiskCacheStrategy.ALL) // 缓存所有版本
.signature(new ObjectKey(signature)) // 使用签名确保缓存一致
.placeholder(R.mipmap.room_bj) // 加载中占位图
.error(R.mipmap.room_bj) // 加载失败占位图
@@ -451,7 +427,7 @@ public class ImageUtils {
* @param listener 回调
*/
public static void loadBitmap(String path, final onLoadBitmap listener) {
Glide.with(Utils.getApp()).asBitmap().load(path).apply(createUrlOnlyOptions(path)).into(new SimpleTarget<Bitmap>() {
Glide.with(Utils.getApp()).asBitmap().load(path).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
@@ -490,8 +466,7 @@ public class ImageUtils {
}
});
}
public static void loadIconByHeight1(String path, ImageView mImageView, int height) {
public static void loadIconByHeight1(String path, ImageView mImageView,int height) {
mImageView.setVisibility(TextUtils.isEmpty(path) ? GONE : View.VISIBLE);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(new SimpleTarget<Drawable>() {
@Override
@@ -515,7 +490,6 @@ public class ImageUtils {
Glide.with(imageView.getContext())
.asBitmap()
.load(url)
.apply(createUrlOnlyOptions(url))
.error(defaultResId) // 加载失败时显示默认图片
.into(new SimpleTarget<Bitmap>() {
@Override
@@ -545,6 +519,8 @@ public class ImageUtils {
}
/**
* 加载bitmap回调
*/
@@ -622,13 +598,12 @@ public class ImageUtils {
// e.printStackTrace();
// }
}
/**
* 将 assets 中的文件复制到指定路径
*
* @param assetName assets 中的文件名,例如:"my_file.txt"
* @param savePath 要保存的目录路径,例如:"/data/data/your.package/files/"
* @param saveName 保存后的文件名
* @param assetName assets 中的文件名,例如:"my_file.txt"
* @param savePath 要保存的目录路径,例如:"/data/data/your.package/files/"
* @param saveName 保存后的文件名
*/
public static void copyAssetToFile(String assetName, String savePath, String saveName) {
InputStream myInput = null;
@@ -680,55 +655,7 @@ public class ImageUtils {
}
}
public static void loadWebpOneStart(int webp_anim, ImageView mAnimView) {
if (mAnimView == null) {
return;
}
// 1. 本地资源专属优化配置
RequestOptions options = new RequestOptions()
// 强制限制解码尺寸为ImageView显示尺寸核心优化
.override(800, 800); // 本地图用原尺寸,或指定固定尺寸
//webp动图
CenterInside transformation = new CenterInside();
Glide.with(mAnimView)
.load(webp_anim)//不是本地资源就改为url即可
.apply(options)
.optionalTransform(transformation)
.optionalTransform(WebpDrawable.class, new WebpDrawableTransformation(transformation))
.addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
WebpDrawable webpDrawable = (WebpDrawable) resource;
//需要设置为循环1次才会有onAnimationEnd回调
webpDrawable.setLoopCount(1);
webpDrawable.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
@Override
public void onAnimationStart(Drawable drawable) {
super.onAnimationStart(drawable);
}
@Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
webpDrawable.unregisterAnimationCallback(this);
}
});
return false;
}
})
.into(mAnimView);
}
public static void clearDiskCache(Context context) {
public static void clearDiskCache(Context context){
Glide.get(context).clearDiskCache();
}

View File

@@ -2,12 +2,8 @@ package com.xscm.moduleutil.utils;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import com.blankj.utilcode.util.LogUtils;
import com.xscm.moduleutil.bean.RedPacketInfo;
import com.xscm.moduleutil.bean.room.EMMessageInfo;
import lombok.Getter;
import lombok.Setter;
@@ -54,16 +50,15 @@ public class QXRedPacketManager {
*
* @param redPackets 红包模型列表
*/
public void addRedPackets(String roomId,List<RedPacketInfo> redPackets) {
public void addRedPackets(List<RedPacketInfo> redPackets) {
if (redPackets == null || redPackets.isEmpty()) {
return;
}
this.redPackets.entrySet().removeIf(entry ->
!(entry.getValue().getRoom_id()+"").equals(roomId));
for (RedPacketInfo model : redPackets) {
this.redPackets.put(model.getRedpacket_id(), model);
}
// 在添加数据后启动定时器(如果尚未启动)
startCheckTimer();
if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) {
@@ -76,18 +71,17 @@ public class QXRedPacketManager {
*
* @param redPacket 红包模型
*/
public void addRedPacket(String roomId,RedPacketInfo redPacket) {
public void addRedPacket(RedPacketInfo redPacket) {
if (redPacket == null || redPacket.getRedpacket_id() == null) {
return;
}
this.redPackets.entrySet().removeIf(entry ->
!(entry.getValue().getRoom_id()+"").equals(roomId));
this.redPackets.put(redPacket.getRedpacket_id(), redPacket);
// 在添加数据后启动定时器(如果尚未启动)
startCheckTimer();
if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) {
this.delegate.onRedPacketAdded(redPacket, this.redPackets.size());
((QXRedPacketManagerDelegate) this.delegate).onRedPacketAdded(redPacket, this.redPackets.size());
}
}
@@ -96,19 +90,11 @@ public class QXRedPacketManager {
*
* @param packetId 红包ID
*/
public void removeRedPacket(int status,String packetId) {
if (status == EMMessageInfo.QXRoomMessageTypeQXRoomMessageRedRemove) {
if (redPackets.get(packetId) != null) {
RedPacketInfo info = redPackets.get(packetId);
if (info.getCountdown() != 0) {
return;
}
}
}
public void removeRedPacket(String packetId) {
this.redPackets.remove(packetId);
if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) {
this.delegate.onRedPacketRemoved(packetId, this.redPackets.size());
((QXRedPacketManagerDelegate) this.delegate).onRedPacketRemoved(packetId, this.redPackets.size());
}
}
@@ -164,6 +150,7 @@ public class QXRedPacketManager {
for (RedPacketInfo packet : packets) {
long packetTime = packet.remainingTime();
LogUtils.e("红包剩余时间:" + packet.getRedpacket_time());
long redpacketTime = 0;
try {
if (packet.getRedpacket_time() != null) {
@@ -172,11 +159,11 @@ public class QXRedPacketManager {
} catch (NumberFormatException e) {
LogUtils.e("红包时间格式错误: " + packet.getRedpacket_time());
}
if (packetTime <= -redpacketTime) {
removeRedPacket(packet.getRedpacket_id());
}
if (packet.getCountdown()==0){
if (packetTime <= -redpacketTime) {
removeRedPacket(0,packet.getRedpacket_id());
}
continue;
}
@@ -193,10 +180,6 @@ public class QXRedPacketManager {
((QXRedPacketManagerDelegate) this.delegate).onRedPacketUpdated(packet, this.redPackets.size());
}
}
if (packetTime <= 0) {
removeRedPacket(0,packet.getRedpacket_id());
}
}
// 继续执行定时任务

View File

@@ -18,7 +18,6 @@ public class SPConstants {
public static final String VOLUME = "VOLUME"; //音量
public static final String CURRENT_MUSIC = "CURRENT_MUSIC"; //当前播放音乐
public static final String OPEN_EFFECT = "OPEN_EFFECT"; //开启特效
public static final String RED_SOUND = "RED_SOUND"; //开启红包声音
public static final String OPEN_AU_BACK = "OPEN_AU_BACK"; //开启耳返
public static final String ORDER_NEWS_COUNT = "orderNewsCount";
public static final String ORDER_LAST_MSG = "lastOrderMsg";
@@ -32,9 +31,7 @@ public class SPConstants {
public static final String USER_INFO = "userInfo";
public static final String FLOATING_SCREEN = "floatingScreen";//飘屏开关
public static final String FLOATING_SCREEN = "floatingScreen";
public static final String SHELF = "shelf";//是否打开趣味玩法
public static final String TASK_SERVICE="taskService";//切换服务器
public static final String SHELF="shelf";
}

View File

@@ -8,7 +8,6 @@ import android.text.TextUtils;
import com.alibaba.fastjson.JSON;
import com.blankj.utilcode.util.SPUtils;
import com.xscm.moduleutil.base.CommonAppContext;
import com.xscm.moduleutil.bean.AppCustomerBean;
import com.xscm.moduleutil.bean.UserBean;
import com.xscm.moduleutil.bean.UserInfo;
@@ -234,16 +233,6 @@ public class SpUtil {
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getString(SPConstants.TOKEN);
}
public static void setAppCustomerBean(AppCustomerBean appCustomerBean) {
String s = JSON.toJSONString(appCustomerBean);
SPUtils.getInstance(SPConstants.PREFERENCE_NAME).put("appCustomerBean", s, true);
}
public static AppCustomerBean getAppCustomerBean() {
String s = SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getString("appCustomerBean");
return JSON.parseObject(s, AppCustomerBean.class);
}
public static void setBoolean(String key, boolean value) {
SPUtils.getInstance(SPConstants.PREFERENCE_NAME).put(key, value, true);
}
@@ -346,14 +335,6 @@ public class SpUtil {
return shelf;
}
public static int setTaskService(int taskService){
SPUtils.getInstance(SPConstants.PREFERENCE_NAME).put(SPConstants.TASK_SERVICE, taskService);
return taskService;
}
public static int getTaskService(){
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getInt(SPConstants.TASK_SERVICE);
}
//获取SharedPreferences音乐轮播方式
public static int getPlayPattern() {
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getInt(SPConstants.PLAY_MODE, 1);
@@ -389,14 +370,6 @@ public class SpUtil {
SPUtils.getInstance(SPConstants.PREFERENCE_NAME).put(SPConstants.OPEN_EFFECT, i);
}
public static void setRedSound(int i){
SPUtils.getInstance(SPConstants.PREFERENCE_NAME).put(SPConstants.RED_SOUND, i);
}
public static int getRedSound(){
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getInt(SPConstants.RED_SOUND, 1);
}
//获取开启特效
public static int getOpenEffect() {
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getInt(SPConstants.OPEN_EFFECT, 1);

View File

@@ -5,6 +5,7 @@ import android.os.Build;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.MetaDataUtils;
import com.chad.library.BuildConfig;
import com.xscm.moduleutil.base.CommonAppContext;
import com.xscm.moduleutil.utils.config.ConfigUtils;
@@ -89,7 +90,7 @@ public class SystemUtils {
ConfigUtils configUtils = ConfigUtils.getInstance(context);
configUtils.setConfigName(system_uuid_key);
String system_config_uuid = configUtils.findStringByKey(system_uuid_key);
if (system_config_uuid == null || system_config_uuid.isEmpty()) {
if (system_config_uuid == null) {
// system_config_uuid = DeviceUtils.getUniqueDeviceId();
configUtils.addOrUpdateText(system_uuid_key, system_config_uuid);
}
@@ -105,9 +106,9 @@ public class SystemUtils {
public static Map<String, String> getSystemParams() {
Map<String, String> headers = new HashMap<>();
headers.put("deviceId", SystemUtils.getShortClientID(CommonAppContext.getInstance()));
headers.put("appId", CommonAppContext.getInstance().appId);
headers.put("versionName", CommonAppContext.getInstance().appVersionName);
headers.put("versionCode", CommonAppContext.getInstance().appVersionCode);
headers.put("appVersion", BuildConfig.VERSION_NAME + "." + BuildConfig.VERSION_CODE);
headers.put("versionName", BuildConfig.VERSION_NAME);
headers.put("versionCode", String.valueOf(BuildConfig.VERSION_CODE));
headers.put("system", "android");
headers.put("emulator", CommonAppContext.getInstance().emulator);
headers.put("deviceName", SystemUtils.getDeviceBrand() + SystemUtils.getSystemModel() + SystemUtils.getSystemVersion());

View File

@@ -168,28 +168,4 @@ public class TextViewUtils {
public interface OnClickableTextListener {
void onClick();
}
/**
* 使用正则表达式格式化手机号中间4位替换为****
* @param phone 原始手机号
* @return 格式化后的手机号
*/
public static String formatPhoneNumberWithRegex(String phone) {
if (phone == null) {
return "";
}
return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
/**
* 处理带区号的手机号中间4位替换为****
* @param phone 原始手机号(可能带区号)
* @return 格式化后的手机号
*/
public static String formatAnyPhone(String phone) {
if (phone == null) {
return "";
}
return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
}

View File

@@ -209,7 +209,7 @@ public class TimeUtils {
//获取当前日期
public static String getCurrentDate2() {
Date d = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddhhmmssSSS");
SimpleDateFormat sf = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss_SSS");
return sf.format(d);
}
/**

View File

@@ -5,7 +5,6 @@ import android.content.SharedPreferences;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class ConfigUtils {
@@ -75,11 +74,8 @@ public class ConfigUtils {
*/
public String findStringByKey(String key) {
if (data_list==null){
data_list = new HashMap<String, Object>();
}
if (data_list.containsKey(key))
return data_list.get(key)!=null?data_list.get(key).toString():"";
return data_list.get(key).toString();
else
return sp.getString(key, null);
}

View File

@@ -15,52 +15,10 @@ public enum EnvironmentEnum {
1600096860,
"3e8f3add448d4692bc1d04c75ffe801b",
//"tcp://1.13.101.98",
// "tcp://1.13.20.30",
"tcp://yushengapi.qxyushen.top",
"tcp://1.13.20.30",
// "https://vespa.qxyushen.top/h5",
"https://yushengapi.qxyushen.top/h5",
0),
// PRODUCTION(//预测版本
// //"https://vespa.qxyushen.top/",
// "https://vsyusheng.qxhs.xyz/", //这是要进行正式服测试的地址
//// "https://yushengapi.qxyushen.top/",
// "KvNmqZc+VMzO4CfGMd5zmG6w6OFwpFO/19TwXUWfHDOBgmnl9DgIuE+kbrjNNnxqhtP3pH7bBrnSaSeFtunr72q6sgpLsfuswcUroMvz2slaTBcNzCaLi+GSnM3gB/GdO47mwLdk+iYBTvPUOCIuT608Z29z09w+vPeUDoMCHJBGXu6uh7Nj6PtV1dfGoUvByk1ZF0WYVjIqKDcb3tXY4jonFh3XAWhzMy8xKwN6F2nuK2IcdIwaSPsvuMZmhatP6f9kOE+vnfweyCHS3RxiG474WIoZGJM8omrl3/pOVqE=",
// "https://oss-cn-beijing.aliyuncs.com/",
// "LTAI5tKgrfcFQxH46ZwWYgFW",
// "ZOjTqAJmUL563EKFKySrUwAHtx4hKt",
// "midi01",
// "https://midi01.oss-cn-beijing.aliyuncs.com/",
// "wxc7681513be9f926b",
//// 1600096860,
// 1600096890,//这是要进行正式服测试的地址
// "3e8f3add448d4692bc1d04c75ffe801b",
// //"tcp://1.13.101.98",
//// "tcp://1.13.20.30",
//// "tcp://yushengapi.qxyushen.top",
// "tcp://vsyusheng.qxhs.xyz", //这是要进行正式服测试的地址
// // "https://vespa.qxyushen.top/h5",
// "https://vsyusheng.qxhs.xyz/h5",
//// "https://yushengapi.qxyushen.top/h5",
// 0),
Auxiliary(//辅助生产环境
//"https://vespa.qxyushen.top/",
"https://details.qxhs.xyz/",
"KvNmqZc+VMzO4CfGMd5zmG6w6OFwpFO/19TwXUWfHDOBgmnl9DgIuE+kbrjNNnxqhtP3pH7bBrnSaSeFtunr72q6sgpLsfuswcUroMvz2slaTBcNzCaLi+GSnM3gB/GdO47mwLdk+iYBTvPUOCIuT608Z29z09w+vPeUDoMCHJBGXu6uh7Nj6PtV1dfGoUvByk1ZF0WYVjIqKDcb3tXY4jonFh3XAWhzMy8xKwN6F2nuK2IcdIwaSPsvuMZmhatP6f9kOE+vnfweyCHS3RxiG474WIoZGJM8omrl3/pOVqE=",
"https://oss-cn-beijing.aliyuncs.com/",
"LTAI5tKgrfcFQxH46ZwWYgFW",
"ZOjTqAJmUL563EKFKySrUwAHtx4hKt",
"midi01",
"https://midi01.oss-cn-beijing.aliyuncs.com/",
"wxc7681513be9f926b",
1600096860,
"3e8f3add448d4692bc1d04c75ffe801b",
//"tcp://1.13.101.98",
// "tcp://1.13.20.30",
"tcp://details.qxhs.xyz",
// "https://vespa.qxyushen.top/h5",
"https://details.qxhs.xyz/h5",
0),
TEST(//测试环境
"https://test.vespa.qxyushen.top/",
"6rdWuz058oq5OahdbFiGEybUcdahd12J83L34Uc7MrPIrxtFG+rXiwDvRcqNvjwbClbbmvMrmxKVkIysFByBsl0Qe9kqd2w8T/nhK5G6eXXlk2V9AjYCieIU+jRnjZBB+Cfechr6rCGJ2aeBARIsXcRPW7wm9WFK9euh5T+v6Pyte68yNaNdcYCll3+U4/uCEog7HygCnMIbAU+kqoPdmn2H+51YOHW+VsnsHd4w1+I3f8Tt0xLIXGM4GWnQueZ5GR46GTWiSYMy8dCIh9SPIMRyC91GosVcfGPMJSdcXqc=",
@@ -72,8 +30,7 @@ public enum EnvironmentEnum {
"wxc7681513be9f926b",
1600096890,
"02f7339ec98947deaeab173599891932",
// "tcp://1.13.181.248",
"tcp://test.vespa.qxyushen.top",
"tcp://1.13.181.248",
"https://test.vespa.qxyushen.top/h5",
1);

View File

@@ -1,131 +0,0 @@
package com.xscm.moduleutil.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.xscm.moduleutil.R;
/**
* 项目名称:羽声语音
* 时间2026/1/4 16:09
* 用途:自定义组件:购买数量,带减少增加按钮
*/
public class AmountView extends LinearLayout implements View.OnClickListener, TextWatcher {
private static final String TAG = "AmountView";
private int amount = 1; //购买数量
private int goods_storage = Integer.MAX_VALUE; //商品库存
private OnAmountChangeListener mListener;
private EditText etAmount;
private Button btnDecrease;
private Button btnIncrease;
public AmountView(Context context) {
this(context, null);
}
public AmountView(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.view_amount, this);
etAmount = (EditText) findViewById(R.id.etAmount);
btnDecrease = (Button) findViewById(R.id.btnDecrease);
btnIncrease = (Button) findViewById(R.id.btnIncrease);
btnDecrease.setOnClickListener(this);
btnIncrease.setOnClickListener(this);
etAmount.addTextChangedListener(this);
TypedArray obtainStyledAttributes = getContext().obtainStyledAttributes(attrs, R.styleable.AmountView);
int btnWidth = obtainStyledAttributes.getDimensionPixelSize(R.styleable.AmountView_btnWidth, LayoutParams.WRAP_CONTENT);
int tvWidth = obtainStyledAttributes.getDimensionPixelSize(R.styleable.AmountView_tvWidth, 80);
int tvTextSize = obtainStyledAttributes.getDimensionPixelSize(R.styleable.AmountView_tvTextSize, 0);
int btnTextSize = obtainStyledAttributes.getDimensionPixelSize(R.styleable.AmountView_btnTextSize, 0);
obtainStyledAttributes.recycle();
LayoutParams btnParams = new LayoutParams(btnWidth, LayoutParams.MATCH_PARENT);
btnDecrease.setLayoutParams(btnParams);
btnIncrease.setLayoutParams(btnParams);
if (btnTextSize != 0) {
btnDecrease.setTextSize(TypedValue.COMPLEX_UNIT_PX, btnTextSize);
btnIncrease.setTextSize(TypedValue.COMPLEX_UNIT_PX, btnTextSize);
}
LayoutParams textParams = new LayoutParams(tvWidth, LayoutParams.MATCH_PARENT);
etAmount.setLayoutParams(textParams);
if (tvTextSize != 0) {
etAmount.setTextSize(tvTextSize);
}
}
public void setOnAmountChangeListener(OnAmountChangeListener onAmountChangeListener) {
this.mListener = onAmountChangeListener;
}
public void setGoods_storage(int goods_storage) {
this.goods_storage = goods_storage;
}
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.btnDecrease) {
if (amount > 1) {
amount--;
etAmount.setText(amount + "");
}
} else if (i == R.id.btnIncrease) {
if (amount < goods_storage) {
amount++;
etAmount.setText(amount + "");
}
}
etAmount.clearFocus();
if (mListener != null) {
mListener.onAmountChange(this, amount);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.toString().isEmpty())
return;
amount = Integer.valueOf(s.toString());
if (amount > goods_storage) {
etAmount.setText(goods_storage + "");
return;
}
if (mListener != null) {
mListener.onAmountChange(this, amount);
}
}
public interface OnAmountChangeListener {
void onAmountChange(View view, int amount);
}
}

View File

@@ -1,11 +1,13 @@
package com.xscm.moduleutil.widget;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SoundEffectConstants;
import android.view.View;
import android.widget.FrameLayout;
@@ -14,14 +16,21 @@ import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import com.blankj.utilcode.util.LogUtils;
import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.cause.ResumeFailedCause;
import com.liulishuo.okdownload.core.listener.DownloadListener1;
import com.liulishuo.okdownload.core.listener.assist.Listener1Assist;
import com.opensource.svgaplayer.SVGACallback;
import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGADynamicEntity;
import com.opensource.svgaplayer.SVGAImageView;
import com.opensource.svgaplayer.SVGAParser;
import com.opensource.svgaplayer.SVGAVideoEntity;
import com.tencent.qgame.animplayer.inter.IAnimListener;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.databinding.RoomViewSvgaAnimBinding;
import com.xscm.moduleutil.utils.SpUtil;
import com.xscm.moduleutil.utils.logger.Logger;
import java.io.File;
@@ -31,8 +40,11 @@ import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@@ -45,9 +57,9 @@ import okhttp3.ResponseBody;
public class AvatarFrameView extends FrameLayout {
private PlaybackManager playbackManager;
private boolean isMute = false;
public void setMute(boolean b) {
this.isMute = b;
}
@@ -56,7 +68,10 @@ public class AvatarFrameView extends FrameLayout {
private RenderType renderType;
private SVGAImageView svgaSurface;
private SVGAImageView svgaSurface2;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private int mType;//1:循环播放 2:播放一次停止播放
private final BlockingQueue<PlayItem> playQueue = new LinkedBlockingQueue<>();
private boolean isPlaying = false;
// 添加销毁标记
@@ -64,6 +79,8 @@ public class AvatarFrameView extends FrameLayout {
private static final String TAG = "AvatarFrameView";
private RoomViewSvgaAnimBinding mBinding;
// 内存监控
private static final long MAX_MEMORY_THRESHOLD = 300 * 1024 * 1024; // 300MB
private static final int MAX_SVGA_CACHE_SIZE = 3;
private final Map<String, WeakReference<SVGAVideoEntity>> svgaCache = new LruCache<>(MAX_SVGA_CACHE_SIZE);
@@ -84,10 +101,25 @@ public class AvatarFrameView extends FrameLayout {
}
private void initViews() {
// if (isDestroyed) return;
// 初始化 ExoPlayer View
// playerView = new PlayerView(getContext());
// playerView.setUseController(false);
// playerView.setVisibility(View.GONE);
// addView(playerView);
// 初始化 SVGA View
svgaSurface = new SVGAImageView(getContext());
svgaSurface.setVisibility(View.GONE);
addView(svgaSurface);
svgaSurface2 = new SVGAImageView(getContext());
svgaSurface2.setVisibility(View.GONE);
addView(svgaSurface2);
// 初始化播放管理器
playbackManager = new PlaybackManager(mainHandler);
}
private String getFileExtension(String url) {
@@ -98,51 +130,186 @@ public class AvatarFrameView extends FrameLayout {
}
return "";
}
public void setSource(String url, int type2) {
// 添加到播放队列
PlayItem item = new PlayItem(url, type2);
processPlayItem(item);
Logger.d("AvatarFrameView", "Added to queue, queue size: url: " + url);
public void playNextFromQueue() {
// if (isDestroyed) return;
// 确保在主线程中执行
// if (Looper.myLooper() != Looper.getMainLooper()) {
// mainHandler.post(this::playNextFromQueue);
// return;
// }
// 检查特效是否开启
// if (SpUtil.getOpenEffect() != 1) {
// clearQueue();
// return;
// }
// 检查是否可以开始新的播放
// if (!playbackManager.canStartNewPlayback()) {
// Logger.d("AvatarFrameView", "Max concurrent playbacks reached, waiting...");
// return;
// }
if (!isPlaying || !isActuallyPlaying()) {
PlayItem item = playQueue.poll();
if (item != null) {
// 通知开始播放
playbackManager.onStartPlayback();
isPlaying = true;
// 处理播放项目
processPlayItem(item);
} else {
isPlaying = false;
Logger.d("AvatarFrameView", "Queue is empty, stop playing");
}
}
}
// 添加统一的播放完成处理方法
public void onPlaybackComplete() {
if (isDestroyed) return;
mainHandler.post(() -> {
// 再次检查是否已销毁
if (isDestroyed) return;
// // 通知播放管理器播放完成
// playbackManager.onFinishPlayback();
// 重置播放状态
isPlaying = false;
// 内存清理检查
// if (playQueue.size() % 5 == 0) {
// performLightMemoryCleanup();
// }
// 继续处理队列中的下一个项目
playNextFromQueue();
});
}
private void processPlayItem(PlayItem item) {
try {
// clearPrevious();
String ext = getFileExtension(item.url);
if ("svga".equalsIgnoreCase(ext)) {
renderType = RenderType.SVGA;
mType = item.type;
if (mBinding != null) {
mBinding.playView.setVisibility(View.GONE);
}
loadSVGA(item.url);
mainHandler.post(() -> {
renderType = RenderType.SVGA;
mType = item.type;
if (mBinding != null && mBinding.playView != null) {
mBinding.playView.setVisibility(View.GONE);
}
loadSVGA(item.url);
});
} else if ("mp4".equalsIgnoreCase(ext)) {
renderType = RenderType.MP4;
mType = item.type;
if (mBinding != null) {
mBinding.playView.setVisibility(View.VISIBLE);
downloadAndPlayMp4(item.url);
} else {
mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.room_view_svga_anim, this, true);
mBinding.playView.setVisibility(View.VISIBLE);
downloadAndPlayMp4(item.url);
}
mainHandler.post(() -> {
renderType = RenderType.MP4;
mType = item.type;
if (mBinding != null && mBinding.playView != null) {
mBinding.playView.setVisibility(View.VISIBLE);
downloadAndPlayMp4(item.url);
}else {
mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.room_view_svga_anim, this, true);
mBinding.playView.setVisibility(View.VISIBLE);
downloadAndPlayMp4(item.url);
}
});
} else {
// 不支持的格式,直接完成
handlePlaybackComplete();
}
} catch (Exception e) {
LogUtils.e(TAG, "Error processing play item: " + e.getMessage());
handlePlaybackComplete();
}
}
// 添加实际播放状态检查方法
private boolean isActuallyPlaying() {
if (renderType == RenderType.SVGA && svgaSurface != null) {
return svgaSurface.isAnimating();
} else if (renderType == RenderType.MP4 && mBinding != null) {
// 检查播放器状态
return mBinding.playView.isRunning();
}
return false;
}
public boolean isPlaying() {
if (mBinding != null) {
if (mBinding != null && mBinding.playView != null) {
return mBinding.playView.isRunning();
}
return true;
}
// 在 AvatarFrameView 类中添加以下代码
private static final int MAX_CONCURRENT_PROCESSING = 3; // 同时处理的最大动画数
private static final int PROCESSING_DELAY = 100; // 处理间隔(毫秒)
private int currentProcessingCount = 0;
public void setSource(String url, int type2) {
// if (isDestroyed) return;
// 确保在主线程中执行
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> setSource(url, type2));
return;
}
// 添加到播放队列
playQueue.add(new PlayItem(url, type2));
Logger.d("AvatarFrameView", "Added to queue, queue size: " + playQueue.size() + ", url: " + url);
if (type2 == 3 || type2 == 1) {
// playNextFromQueue();
loadSVGA(url);
} else {
// 如果当前没有在播放,则开始播放
if (!isPlaying || !isActuallyPlaying()) {
playNextFromQueue();
}
}
Logger.d("AvatarFrameView", "Added to queue, queue size: " + playQueue.size() + ", url: " + url);
}
private void smartCheckAndStartPlayback() {
// 检查是否可以开始新的播放任务
if (!playQueue.isEmpty() &&
(!isPlaying || !isActuallyPlaying()) &&
currentProcessingCount < MAX_CONCURRENT_PROCESSING) {
currentProcessingCount++;
playNextFromQueue();
}
}
private void checkAndStartPlayback() {
// 如果队列不为空且当前没有在播放,则开始播放
if (!playQueue.isEmpty() && (!isPlaying || !isActuallyPlaying())) {
playNextFromQueue();
}
}
private boolean isMemoryLow() {
Runtime runtime = Runtime.getRuntime();
long usedMemory = runtime.totalMemory() - runtime.freeMemory();
long maxMemory = runtime.maxMemory();
double memoryUsage = (double) usedMemory / maxMemory;
// 内存使用超过80%或绝对使用量超过阈值
return memoryUsage > 0.8 || usedMemory > MAX_MEMORY_THRESHOLD;
}
boolean isTxk = false;
public void downloadAndPlayMp4(String url) {
// 提取文件名
String fileName = url.substring(url.lastIndexOf("/"));
String filePath = getContext().getCacheDir().getAbsolutePath() + fileName;
@@ -163,6 +330,12 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onFailure(Call call, IOException e) {
LogUtils.e("MP4下载失败: " + e.toString());
mainHandler.post(() -> {
// 检查是否已销毁
if (!isDestroyed) {
onPlaybackComplete();
}
});
}
// 更简单的优化版本
@@ -198,36 +371,63 @@ public class AvatarFrameView extends FrameLayout {
fos.flush();
isTxk = true;
// 关键在执行UI操作前再次检查是否已销毁
if (downloadedFile.exists()) {
LogUtils.d("@@@@Thread", Thread.currentThread().getName());
playMp4File(downloadedFile); // 使用正确的文件引用
} else {
LogUtils.w(TAG, "View destroyed or file not exist after download");
}
mainHandler.post(() -> {
// 关键在执行UI操作前再次检查是否已销毁
if (downloadedFile.exists()) {
LogUtils.d("@@@@Thread", Thread.currentThread().getName());
playMp4File(downloadedFile); // 使用正确的文件引用
} else {
LogUtils.w(TAG, "View destroyed or file not exist after download");
onPlaybackComplete();
}
});
} catch (IOException e) {
LogUtils.e("MP4文件保存失败: " + e.getMessage());
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
}
} else {
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
}
} catch (Exception e) {
LogUtils.e("MP4文件保存失败: " + e.getMessage());
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
}
} else {
LogUtils.e("MP4下载响应失败");
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
}
}
});
} else {
isTxk = true;
// 检查是否已销毁
if (file.exists()) {
LogUtils.e("有缓存:" + file.exists() + "====" + file.getAbsolutePath());
playMp4File(file);
} else {
LogUtils.w(TAG, "有缓存2222222222222");
}
LogUtils.e("有缓存");
mainHandler.post(() -> {
// 检查是否已销毁
if (file.exists()) {
LogUtils.e("有缓存:"+file.exists()+"===="+file.getAbsolutePath());
playMp4File(file);
} else {
LogUtils.w(TAG, "有缓存2222222222222");
}
});
}
}
@@ -236,11 +436,13 @@ public class AvatarFrameView extends FrameLayout {
// 双重检查确保组件未被销毁
if (isDestroyed) {
LogUtils.w(TAG, "Attempt to play MP4 file after view destroyed");
onPlaybackComplete();
return;
}
if (mBinding == null) {
if (mBinding == null || mBinding.playView == null) {
LogUtils.w(TAG, "PlayView is null");
onPlaybackComplete();
return;
}
@@ -251,23 +453,27 @@ public class AvatarFrameView extends FrameLayout {
} else {
mBinding.playView.setLoop(1); // 播放一次
}
mBinding.playView.setMute(isMute);
mBinding.playView.setMute(isMute);
// 开始播放前检查视图状态
if (!isDestroyed && mBinding != null && mBinding.playView != null) {
mBinding.playView.startPlay(file);
} else {
LogUtils.w(TAG, "View was destroyed before MP4 playback started");
onPlaybackComplete();
}
} else {
LogUtils.e("播放MP4文件出错: 文件不存在或已损坏");
onPlaybackComplete();
}
} catch (Exception e) {
LogUtils.e("播放MP4文件出错: " + e.getMessage());
onPlaybackComplete();
}
}
private void handleSVGAComplete(SVGAVideoEntity videoItem, String url) {
if (svgaSurface == null) {
onPlaybackComplete();
return;
}
@@ -290,6 +496,7 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.stopAnimation();
svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null);
onPlaybackComplete();
}
}
@@ -299,8 +506,11 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onFinished() {
// if (isDestroyed) return;
if (mType == 1) { // 循环播放
// 继续循环播放
} else {
onPlaybackComplete();
}
}
});
@@ -313,6 +523,10 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.startAnimation();
} catch (Exception e) {
LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage());
// isPlaying = false;
// playNextFromQueue();
handlePlaybackComplete();
}
}
@@ -322,8 +536,13 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null);
}
if (svgaSurface2 != null) {
svgaSurface2.stopAnimation();
svgaSurface2.clearAnimation();
svgaSurface.setImageDrawable(null);
}
// 增加空值检查
if (mBinding != null) {
if (mBinding != null && mBinding.playView != null) {
mBinding.playView.stopPlay();
}
}
@@ -347,7 +566,16 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onFinished() {
isPlaying = false;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
// 添加延迟确保状态更新
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
});
} else {
isPlaying = false;
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
}
}
});
// 设置循环次数
@@ -360,16 +588,21 @@ public class AvatarFrameView extends FrameLayout {
} catch (Exception e) {
LogUtils.e(TAG, "Error playing cached SVGA: " + e.getMessage());
isPlaying = false;
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
// playNextFromQueue();
}
}
private void loadNewSVGA(String url) {
try {
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
@Override
public void onComplete(SVGAVideoEntity videoItem) {
// if (isDestroyed) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
handleSVGAComplete(videoItem, url);
mainHandler.post(() -> handleSVGAComplete(videoItem, url));
} else {
handleSVGAComplete(videoItem, url);
}
@@ -377,16 +610,32 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onError() {
isPlaying = false;
// if (isDestroyed) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
playNextFromQueue();
});
} else {
isPlaying = false;
playNextFromQueue();
}
}
});
} catch (Exception e) {
LogUtils.e(TAG, "Error parsing SVGA: " + e.getMessage());
isPlaying = false;
playNextFromQueue();
}
}
private void loadSVGA(String url) {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> loadSVGA(url));
return;
}
try {
svgaSurface.setVisibility(View.VISIBLE);
@@ -397,7 +646,6 @@ public class AvatarFrameView extends FrameLayout {
if (cachedEntity != null) {
// 使用缓存的实体
playCachedSVGA(cachedEntity);
return;
} else {
// 加载新的SVGA
loadNewSVGA(url);
@@ -405,49 +653,52 @@ public class AvatarFrameView extends FrameLayout {
} catch (Exception e) {
LogUtils.e(TAG, "Error loading SVGA: " + e.getMessage());
isPlaying = false;
playNextFromQueue();
}
// svgaSurface.setVisibility(View.VISIBLE);
// try {
// new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
// @Override
// public void onComplete(SVGAVideoEntity videoItem) {
// SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity());
// svgaSurface.setImageDrawable(drawable);
// svgaSurface.setCallback(new SVGACallback() {
//
// @Override
// public void onStep(int i, double v) {
//
// }
//
// @Override
// public void onRepeat() {
//
// }
//
// @Override
// public void onPause() {
//
// }
//
// @Override
// public void onFinished() {
// isPlaying = false;
// }
// });
//
// svgaSurface.startAnimation();
// }
//
// @Override
// public void onError() {
// isPlaying = false;
// }
// });
// } catch (Exception e) {
// e.printStackTrace();
// }
svgaSurface.setVisibility(View.VISIBLE);
try {
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
@Override
public void onComplete(SVGAVideoEntity videoItem) {
SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity());
svgaSurface.setImageDrawable(drawable);
svgaSurface.setCallback(new SVGACallback() {
@Override
public void onStep(int i, double v) {
}
@Override
public void onRepeat() {
}
@Override
public void onPause() {
}
@Override
public void onFinished() {
isPlaying = false;
playNextFromQueue();
}
});
svgaSurface.startAnimation();
}
@Override
public void onError() {
isPlaying = false;
playNextFromQueue();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@@ -465,6 +716,7 @@ public class AvatarFrameView extends FrameLayout {
}
// 隐藏所有视图
// if (playerView != null) playerView.setVisibility(View.GONE);
if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
@@ -498,7 +750,39 @@ public class AvatarFrameView extends FrameLayout {
*/
private void releaseResources() {
LogUtils.d(TAG, "Releasing all resources");
performUICleanup();
// if (isDestroyed) return;
// 使用异步线程处理耗时操作
new Thread(() -> {
try {
// 在后台线程处理文件操作和大对象清理
// performHeavyCleanup();
// 回到主线程处理 UI 相关的清理
mainHandler.post(() -> {
performUICleanup();
});
} catch (Exception e) {
Logger.e(TAG, "Error in async releaseResources: " + e.getMessage());
// 出错时仍在主线程清理 UI 资源
mainHandler.post(() -> {
performUICleanup();
});
}
}).start();
}
/**
* 在后台线程执行耗时的清理操作
*/
private void performHeavyCleanup() {
try {
// 清理缓存文件(如果需要)
// 清理大对象引用等
// clearCacheFiles();
} catch (Exception e) {
Logger.e(TAG, "Error in performHeavyCleanup: " + e.getMessage());
}
}
/**
@@ -507,16 +791,31 @@ public class AvatarFrameView extends FrameLayout {
private void performUICleanup() {
try {
// 停止并清理播放器
if (mBinding != null) {
if (mBinding != null && mBinding.playView != null) {
try {
mBinding.playView.stopPlay();
} catch (Exception e) {
Logger.e(TAG, "Error stopping playView: " + e.getMessage());
}
}
// 清理 ExoPlayer 资源
// if (exoPlayer != null) {
// try {
// // 使用异步停止避免阻塞
// exoPlayer.stop();
// exoPlayer.clearVideoSurface();
// } catch (Exception e) {
// Logger.e(TAG, "Error releasing ExoPlayer resources: " + e.getMessage());
// }
// }
// 清理 SVGA 资源
if (svgaSurface != null) {
try {
// svgaSurface.pauseAnimation();
// svgaSurface.clearAnimation();
// svgaSurface.setImageDrawable(null);
svgaSurface.stopAnimation(true);
svgaSurface.clear();
svgaSurface.clearAnimation();
@@ -535,23 +834,86 @@ public class AvatarFrameView extends FrameLayout {
*/
public void release() {
Logger.d("AvatarFrameView", "Public release called");
// if (isDestroyed) return;
// 确保在主线程中执行
// if (Looper.myLooper() != Looper.getMainLooper()) {
// mainHandler.post(this::release);
// return;
// }
isDestroyed = true;
try {
// 清空播放队列
clearQueue();
// 清理播放管理器
if (playbackManager != null) {
playbackManager.reset();
}
// 释放所有资源
releaseResources();
// 延迟清理其他资源
mainHandler.postDelayed(() -> {
// 清理 binding
if (mBinding != null) {
mBinding = null;
}
}, 100);
// 清理 binding
if (mBinding != null) {
mBinding = null;
}
} catch (Exception e) {
LogUtils.e(TAG, "Error in AvatarFrameView release: " + e.getMessage());
} finally {
// 建议进行垃圾回收
// MemoryOptimizationUtils.forceGC();
}
}
public void clearQueue() {
// if (isDestroyed) return;
playQueue.clear();
isPlaying = false;
// 清理播放管理器中的任务
if (playbackManager != null) {
playbackManager.reset();
}
// 清理当前正在播放的内容
clearPrevious();
}
// 在类成员变量中添加
private static final int PLAYBACK_TIMEOUT = 10000; // 10秒超时
private Map<String, Long> playbackStartTimeMap = new HashMap<>();
// 添加超时检查方法
private void startPlaybackTimeout(String url) {
playbackStartTimeMap.put(url, System.currentTimeMillis());
mainHandler.postDelayed(() -> checkPlaybackTimeout(url), PLAYBACK_TIMEOUT);
}
private void checkPlaybackTimeout(String url) {
Long startTime = playbackStartTimeMap.get(url);
if (startTime != null && System.currentTimeMillis() - startTime > PLAYBACK_TIMEOUT) {
LogUtils.w(TAG, "Playback timeout: " + url);
playbackStartTimeMap.remove(url);
// 强制结束当前播放并继续下一个
handlePlaybackComplete();
}
}
private void cancelPlaybackTimeout(String url) {
playbackStartTimeMap.remove(url);
}
private static class PlayItem {
String url;
int type;
@@ -561,4 +923,167 @@ public class AvatarFrameView extends FrameLayout {
this.type = type;
}
}
/**
* 关闭特效
*/
public void closeEffect() {
// 清空队列
clearQueue();
// 释放资源
// releaseResources();
// 清空队列
// playQueue.clear();
// 关闭动画
// if (mBinding.playView != null && isPlaying && mBinding.playView.isRunning()) {
// mBinding.playView.setAnimation(null);
// mBinding.playView.clearAnimation();
// mBinding.playView.stopPlay();
// }
}
/**
* 开始循环播放SVGA动画
*/
public void startLoopingSvga(String assetName) {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> startLoopingSvga(assetName));
return;
}
try {
// clearPrevious(); // 清除之前的动画
svgaSurface.setVisibility(View.VISIBLE);
new SVGAParser(getContext()).decodeFromAssets(assetName, new SVGAParser.ParseCompletion() {
@Override
public void onComplete(SVGAVideoEntity svgaVideoEntity) {
SVGADrawable drawable = new SVGADrawable(svgaVideoEntity);
svgaSurface.setImageDrawable(drawable);
svgaSurface.setLoops(0); // 0表示无限循环
svgaSurface.startAnimation();
}
@Override
public void onError() {
Log.e(TAG, "解析SVGA文件失败: " + assetName);
}
});
} catch (Exception e) {
Log.e(TAG, "播放SVGA动画出错", e);
}
}
/**
* 停止并销毁当前SVGA动画
*/
public void stopSvga() {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> stopSvga());
return;
}
try {
if (svgaSurface2 != null) {
svgaSurface2.stopAnimation(true);
svgaSurface2.setImageDrawable(null);
svgaSurface2.setVisibility(View.GONE);
}
} catch (Exception e) {
Log.e(TAG, "停止SVGA动画出错", e);
}
}
// 在 AvatarFrameView 类中添加以下代码
// 播放任务管理器
// 替换现有的 PlaybackManager 类
private static class PlaybackManager {
private static final int MAX_CONCURRENT_PLAYBACKS = 3; // 增加并发数
private int currentPlaybackCount = 0;
private final Handler handler;
public PlaybackManager(Handler handler) {
this.handler = handler;
}
public boolean canStartNewPlayback() {
return currentPlaybackCount < MAX_CONCURRENT_PLAYBACKS;
}
public void onStartPlayback() {
currentPlaybackCount++;
}
public void onFinishPlayback() {
currentPlaybackCount = Math.max(0, currentPlaybackCount - 1);
}
public void reset() {
currentPlaybackCount = 0;
}
}
// 播放任务接口
private interface PlaybackTask {
void execute();
}
// 在 AvatarFrameView 类中添加以下代码
// private IAnimListener MP4PlaybackCallback;
// 在 AvatarFrameView 类的成员变量区域添加单例实例
public void setAnimListener(IAnimListener mInstance) {
mBinding.playView.setAnimListener(mInstance);
}
// 添加统一的播放完成处理方法
private void handlePlaybackComplete() {
mainHandler.post(() -> {
if (isDestroyed) return;
isPlaying = false;
// 通知播放管理器任务完成
if (playbackManager != null) {
playbackManager.reset();
}
// 内存检查
if (playQueue.size() % 5 == 0) {
// performLightMemoryCleanup();
}
// 播放下一个
playNextFromQueue();
});
}
// 添加轻量级内存清理方法
private void performLightMemoryCleanup() {
Runtime runtime = Runtime.getRuntime();
long usedMemory = runtime.totalMemory() - runtime.freeMemory();
long maxMemory = runtime.maxMemory();
double memoryUsage = (double) usedMemory / maxMemory;
// 内存使用超过70%时进行清理
if (memoryUsage > 0.7) {
// 清理SVGA缓存
if (svgaCache.size() > 1) {
// 保留最新的缓存项
Iterator<Map.Entry<String, WeakReference<SVGAVideoEntity>>> iterator =
svgaCache.entrySet().iterator();
if (iterator.hasNext()) {
iterator.next(); // 跳过最新的
if (iterator.hasNext()) {
iterator.remove(); // 移除较旧的
}
}
}
// 建议进行垃圾回收
System.gc();
}
}
}

View File

@@ -14,7 +14,6 @@ import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGAImageView;
import com.opensource.svgaplayer.SVGAParser;
@@ -38,7 +37,6 @@ import com.xscm.moduleutil.event.RoomFaceEvent;
import com.xscm.moduleutil.interfaces.IBaseWheat;
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
import com.xscm.moduleutil.rtc.AgoraManager;
import com.xscm.moduleutil.utils.ImageUtils;
import com.xscm.moduleutil.utils.SpUtil;
import com.xscm.moduleutil.utils.logger.Logger;
@@ -51,7 +49,7 @@ import java.net.URL;
public abstract class BaseWheatView extends ConstraintLayout implements IBaseWheat {
public ImageView mRiv;
public ImageView mIvGift;
public WheatCharmView mCharmView;
public TextView mTvName;
public ImageView mIvSex;
@@ -65,7 +63,6 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
public TextView tv_time_pk;
public RoomPitBean pitBean;//麦位数据
public String roomId;//房间id
CountDownTimer mCountDownTimer;
@@ -74,6 +71,9 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
public static final String WHEAT_HOST = "9";//主持位
public float oX;
public float oY;
boolean closePhone = false;//自己麦位关闭话筒,用于判断声纹显示
public String pitNumber;
@@ -82,14 +82,17 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
public ImageView iv_on_line;
private boolean showGiftAnim = true;//显示麦位动画
private ImageView iv_tag_type;
// 当前音量监听器,用于防止重复添加
private SoundLevelUpdateListener currentSoundLevelListener;
private TextView tv_zhul;
private SVGAParser mParser;
private String micCycle = "";
private final SVGAParser parser = new SVGAParser(CommonAppContext.getInstance());
public boolean isMentorShip = false;
private SoundLevelUpdateListener soundLevelUpdateListener;
public BaseWheatView(Context context) {
this(context, null, 0);
@@ -103,13 +106,12 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
super(context, attrs, defStyleAttr);
inflate(context, getLayoutId(), this);
mRiv = findViewById(R.id.riv);
// mIvGift = findViewById(R.id.iv_gift);
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);
@@ -120,6 +122,8 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
tv_zhul = findViewById(R.id.tv_zhul);
setClipChildren(false);
setClipToPadding(false);
oX = mIvGift.getX();
oY = mIvGift.getY();
initPit(context, attrs);
}
@@ -175,63 +179,33 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
setCardiac(pitBean.getCharm(), getTzbl());
if (bean.getUser_id() != null && !bean.getUser_id().equals("0") && !bean.getUser_id().isEmpty()) {
if (bean.getIs_online() == 1) {
iv_on_line.setVisibility(GONE);
} else if (bean.getIs_online() == 2) {
if (!bean.getUser_id().equals(SpUtil.getUserId() + "")) {
iv_on_line.setVisibility(VISIBLE);
}
} else {
iv_on_line.setVisibility(GONE);
}
if (bean.getIs_online()==1){
iv_on_line.setVisibility(GONE);
}else if (bean.getIs_online()==2){
if (!bean.getUser_id().equals(SpUtil.getUserId()+"")) {
iv_on_line.setVisibility(VISIBLE);
}
}else {
iv_on_line.setVisibility(GONE);
}
} else {
iv_on_line.setVisibility(GONE);
}
if (mParser == null || (!TextUtils.isEmpty(pitBean.getMic_cycle()) && !micCycle.equals(pitBean.getMic_cycle()))) {
LogUtils.e("这是一个很诡异的东西 " + (mParser == null) + ",pitBean.getMic_cycle():" + pitBean.getMic_cycle());
if (mParser != null) {
mParser = null;
mIvRipple.stopAnimation(); // 停止当前播放的动画
mIvRipple.setVideoItem(null);
}
micCycle = pitBean.getMic_cycle();
mParser = new SVGAParser(getContext());
if (TextUtils.isEmpty(pitBean.getMic_cycle())) {
mParser.decodeFromAssets("mic.svga", new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@Nullable SVGAVideoEntity videoItem) {
if (videoItem != null) {
mIvRipple.setVideoItem(videoItem);
}
}
@Override
public void onError() {
Log.e("SVGA", "解析 ripple.svga 失败");
}
});
} else {
try {
mParser.decodeFromURL(new URL(pitBean.getMic_cycle()),
new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
mIvRipple.setImageDrawable(new SVGADrawable(svgaVideoEntity));
mIvRipple.startAnimation();
}
@Override
public void onError() {
LogUtils.e("BaseWheatView", "解析 mic_cycle 失败");
}
});
} catch (MalformedURLException ignored) {
LogUtils.e("BaseWheatView", "解析 mic_cycle 失败");
parser.decodeFromAssets("mic.svga", new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@Nullable SVGAVideoEntity videoItem) {
if (videoItem != null) {
mIvRipple.setVideoItem(videoItem);
}
}
}
@Override
public void onError() {
Log.e("SVGA", "解析 ripple.svga 失败");
}
});
setPitData(bean);
@@ -240,7 +214,8 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
mIvRipple.setScaleX(1.1f);
mIvRipple.setScaleY(1.1f);
}
if (!isMentorShip) {
if (!isMentorShip){
//心动值
//显示心动
if ("1".equals(pitBean.getShutup())) {
@@ -284,23 +259,102 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
}
}
if (soundLevelUpdateListener != null) {
AgoraManager.getInstance().removeSoundLevelListener(soundLevelUpdateListener);
}
soundLevelUpdateListener = new SoundLevelUpdateListener() {
AgoraManager.getInstance().addSoundLevelListener(new SoundLevelUpdateListener() {
@Override
public void onRemoteSoundLevelUpdate(String userId, int soundLevel) {
if (mIvRipple == null || pitBean.getUser_id().equals("0")) return;
if (!userId.equals(pitBean.getUser_id())) return;
if (mIvRipple == null)
return;
boolean nowSpeaking = soundLevel > 0;
if (userId.equals(pitBean.getUser_id())) {
if (soundLevel == 0) {
mIvRipple.pauseAnimation();
CommonAppContext.getInstance().onlineMap.put(pitBean.getUser_id(), 1);
mIvRipple.setVisibility(INVISIBLE);
} else {
mIvRipple.setVisibility(VISIBLE);
mIvRipple.post(() -> {
if (!mIvRipple.isAnimating()) {
if (pitBean.getMic_cycle() != null && !pitBean.getMic_cycle().isEmpty()) {
if (mParser != null) {
mIvRipple.startAnimation();
} else {
mParser = new SVGAParser(getContext());
try {
mParser.decodeFromURL(new URL(pitBean.getMic_cycle()), new SVGAParser.ParseCompletion() {
updateSpeakingState(nowSpeaking);
@Override
public void onError() {
}
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
if (mIvRipple == null)
return;
SVGADrawable drawable = new SVGADrawable(svgaVideoEntity);
mIvRipple.setImageDrawable(drawable);
mIvRipple.startAnimation();
}
});
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
} else {
mIvRipple.startAnimation();
}
CommonAppContext.getInstance().onlineMap.put(pitBean.getUser_id(), 1);
iv_on_line.setVisibility(GONE);
}
});
}
}
}
@Override
public void onLocalSoundLevelUpdate(int volume) {
if (mIvRipple == null)
return;
if (volume == 0) {
mIvRipple.setVisibility(GONE);
} else {
mIvRipple.setVisibility(VISIBLE);
if (!mIvRipple.isAnimating()) {
if (pitBean.getMic_cycle()!=null && !pitBean.getMic_cycle().isEmpty()) {
if (mParser != null) {
mIvRipple.startAnimation();
} else {
mParser = new SVGAParser(getContext());
try {
mParser.decodeFromURL(new URL(pitBean.getMic_cycle()), new SVGAParser.ParseCompletion() {
@Override
public void onError() {
}
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
if (mIvRipple == null)
return;
SVGADrawable drawable = new SVGADrawable(svgaVideoEntity);
mIvRipple.setImageDrawable(drawable);
mIvRipple.startAnimation();
}
});
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}else {
mIvRipple.startAnimation();
}
CommonAppContext.getInstance().onlineMap.put(pitBean.getUser_id(), 1);
iv_on_line.setVisibility(GONE);
}
}
}
@Override
@@ -318,79 +372,15 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
if (String.valueOf(uid).equals(pitBean.getUser_id())) {
if (mIvRipple == null)
return;
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
mIvRipple.setVisibility(INVISIBLE);
}
});
Log.e("SVGA", "-------" + pitBean.getUser_id());
mIvRipple.setVisibility(GONE);
}
}
};
});
AgoraManager.getInstance().addSoundLevelListener(soundLevelUpdateListener);
}
private boolean isSpeaking = false;
private void updateSpeakingState(boolean nowSpeaking) {
// 1⃣ 状态未变化,直接丢弃(核心)
// if (nowSpeaking == isSpeaking) return;
isSpeaking = nowSpeaking;
if (!nowSpeaking) {
// 静音状态
mIvRipple.pauseAnimation();
mIvRipple.setVisibility(INVISIBLE);
return;
}
// 2⃣ 开始说话(只触发一次)
mIvRipple.setVisibility(VISIBLE);
iv_on_line.setVisibility(GONE);
CommonAppContext.getInstance().onlineMap.put(pitBean.getUser_id(), 1);
if (!mIvRipple.isAnimating()) {
startRippleAnimation();
}
}
private void startRippleAnimation() {
if (mParser != null) {
mIvRipple.startAnimation();
return;
}
if (pitBean.getMic_cycle() == null || pitBean.getMic_cycle().isEmpty()) {
mIvRipple.startAnimation();
return;
}
try {
mParser = new SVGAParser(getContext());
mParser.decodeFromURL(new URL(pitBean.getMic_cycle()),
new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
if (mIvRipple == null) return;
mIvRipple.setImageDrawable(new SVGADrawable(svgaVideoEntity));
mIvRipple.startAnimation();
}
@Override
public void onError() {
}
});
} catch (MalformedURLException ignored) {
}
}
public void setCharm(String charm) {
if (pitBean != null && pitBean.getSex() != null)
mCharmView.setSex(pitBean.getSex(), pitBean.getUser_id(), charm, false);
mCharmView.setSex(pitBean.getSex(), pitBean.getUser_id(), charm, false);
}
/**
@@ -436,25 +426,15 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
}
}
public void setTime(String time) {
if (TextUtils.isEmpty(time)) {
tvTime.setText("");
tvTime.setVisibility(View.INVISIBLE);
} else {
tvTime.setText(time);
tvTime.setVisibility(View.VISIBLE);
}
}
public void setOnlineStatus() {
if (pitBean.getUser_id() != null && !pitBean.getUser_id().equals("0") && !pitBean.getUser_id().isEmpty()) {
if (pitBean.getIs_online() == 1) {
if (pitBean.getIs_online()==1){
iv_on_line.setVisibility(GONE);
} else if (pitBean.getIs_online() == 2) {
if (!pitBean.getUser_id().equals(SpUtil.getUserId() + "")) {
}else if (pitBean.getIs_online()==2){
if (!pitBean.getUser_id().equals(SpUtil.getUserId()+"")) {
iv_on_line.setVisibility(VISIBLE);
}
} else {
}else {
iv_on_line.setVisibility(GONE);
}
} else {
@@ -473,7 +453,6 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
showGiftAnim = false;
releaseCountDownTimer();
super.onDetachedFromWindow();
mParser = null;
}
/**
@@ -506,7 +485,14 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
@Subscribe(threadMode = ThreadMode.MAIN)
@Override
public void showGift(RoomGiveGiftModel.GiftListBean listBean) {
if (!showGiftAnim) {
mIvGift.setVisibility(GONE);
return;
}
if (listBean.getUser_id() == null || !listBean.getUser_id().equals(pitBean.getUser_id())) {
return;
}
WheatGiftAnim.addGift(mIvGift, listBean.getPicture());
}
/**
@@ -786,6 +772,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
mIvFace.addData(new FaceBean(roomRollModel.getNumber(), 2));
}
/**
* 是否主持
*

View File

@@ -225,9 +225,6 @@ public class Constants {
public static final String GET_REWARD_LIST = "/api/UserZone/reward_list";//动态打赏列表
public static final String GET_GIFT_LABEL = "/api/Gift/get_gift_label";//礼物标签
public static final String GIFT_LIST = "/api/Gift/get_gift_list";//礼物列表
public static final String GET_CUSTOM_GIFT_LIST = "/api/GiftNew/get_custom_gift_list";//自定义礼物列表
public static final String GET_NEW_GIFT_LIST = "/api/GiftNew/get_gift_list";//新礼物列表
public static final String SET_CUSTOM_GIFT = "/api/GiftNew/set_custom_gift";//自定义礼物设置
public static final String TOPIC_LIST = "/api/UserZone/topic_list";//获取话题列表
public static final String PUBLISH_ZONE = "/api/UserZone/publish_zone";//发布动态
public static final String GET_CATEGORIES = "/api/UserZone/get_zone_topic";//动态引用的四条话题
@@ -244,10 +241,7 @@ public class Constants {
public static final String CANCEL = "/api/Login/cancel";//注销账号
public static final String POST_MODIFY_HIDE_STATUS = "/api/UserData/modify_hide_status";//设置隐身进入
public static final String GET_MY_INFO = "/api/User/get_user_info";//点击我的获取个人数据
public static final String GET_APP_CUSTOMER_SERVICE = "/api/banner/app_customer_service";//获取平台客服用户Id
public static final String GET_USER_HOME = "/api/User/get_user_home";//点击获取个人数据
public static final String POST_DEL_SONG = "/api/RoomSong/del_song";//删除已点歌曲
public static final String POST_SEARCH_USER = "/api/RoomSong/search_song";//已点列表搜索
public static final String ED_USER_INFO = "/api/User/edit_user_info";//编辑信息
public static final String ED_USER_BG = "/api/User/edit_user_bg";//编辑背景图片
@@ -264,14 +258,9 @@ public class Constants {
public static final String LIKE_ALBUM = "/api/User/like_album";//相册点赞
public static final String GET_PERSONALTY = "/api/Decorate/get_type_list";//装扮类型列表
public static final String GET_DECORATE = "/api/Decorate/user_decorate";//装扮详情
public static final String GET_DECORATE_DETAIL = "/api/Decorate/get_decorate_detail";//装饰价格详情
public static final String POST_PAY_DECORATE = "/api/Decorate/pay_decorate";//购买装扮
public static final String SET_USER_DECORATE = "/api/Decorate/set_user_decorate";//用户装扮
public static final String JOIN_ROOM = "/api/Room/join_room";//加入房间
public static final String BEFORE_JOIN_ROOM_CHECK = "/api/Room/before_join_room_check";//加入房间前检查
public static final String TASK_JUMP_ROOM = "/api/Room/task_jump_room";//师徒任务 加入房间
public static final String GET_PIT_TIME = "/api/BarRoom/get_pit_time_list";//酒吧房麦位时长列表
public static final String POST_BLACK_ROOM_LIST = "/api/BarRoom/black_room_list";//小黑屋(酒吧房,交友小屋)列表
public static final String UPDATEPASSWORD = "/api/room/setRoomPassword";//更新房间秘密啊
public static final String GET_ROOM_ONLINE = "/api/Room/room_online_list";//房间在线列表
@@ -283,16 +272,13 @@ public class Constants {
public static final String GET_ROOM_TYPE = "/api/Index/room_type_list";//房间分类列表
public static final String GET_GIVE_GIFT = "/api/Gift/chat_gift_send";//聊天送礼物
public static final String GET_WALLET = "/api/UserWallet/wallet";//钱包
public static final String GET_TASKS_MESSAGE = "/api/Tasks/dailyTasksUnReceiveCount";//【新】未领取奖励任务数量
public static final String GET_REDPACKET_CONFIG = "/api/Redpacket/appConfig";//红包配置信息接口
public static final String REDPACKET_CREATE = "/api/Redpacket/create";//创建红包
public static final String ROOM_REDPACKET = "/api/Redpacket/roomRedPackets";//红包列表
public static final String GET_REDPACKET_DETAIL = "/api/Redpacket/detail";//红包详情
public static final String POST_GRAB = "/api/Redpacket/grab";//抢红包
// public static final String GET_ROOM_GIFT = "/api/Room/room_give_gift";//直播间送礼
public static final String GET_ROOM_GIFT = "/api/SendGift/send_gift";//直播间送礼
public static final String GET_ROOM_GIFT = "/api/Room/room_give_gift";//直播间送礼
public static final String POST_CP_GIVE_GIFT = "/api/UserCp/cpGiveGift";//用户CP礼物回赠
public static final String GET_CP_ZONE = "/api/UserCp/cpZone";//心动空间
public static final String POST_MY_FAMILY = "/api/Family/myFamily";//我的家族
@@ -300,9 +286,6 @@ public class Constants {
public static final String POST_FAMILY_EARNINGS = "/api/Family/familyEarnings";//家族收益详情
public static final String GET_ROOM_USER = "/api/Room/room_user_home";//房间内点击头像
public static final String APPLY_PIT = "/api/RoomPit/apply_pit";//申请上麦
public static final String POST_LIAO_TA = "/api/BarRoom/liao_ta";//撩他
public static final String GET_GIFT_INFO_TA = "/api/BarRoom/get_gift_info_ta";//约她获取礼物详情
public static final String POST_MEETING_TA = "/api/BarRoom/meeting_ta";//约她进房间
public static final String DOWN_PIT = "/api/RoomPit/down_pit";//下麦
public static final String ADDRESS_IP = "/api/User/update_user_ip";//修改ip地址
public static final String REWARD_ZONE = "/api/UserZone/reward_zone";//动态打赏礼物
@@ -316,7 +299,6 @@ public class Constants {
public static final String HELP_APPLY = "/api/RoomPit/help_apply_pit";//上麦助力
public static final String POST_APPLY_SONG = "/api/RoomSong/apply_song";//申请点歌
public static final String POST_AGREE_SONG = "/api/RoomSong/agree_song";//同意、拒绝点歌
public static final String GET_BLIND_BOX_STATUS = "/api/BlindBoxTurntable/blind_box_status";//盲盒转盘状态
public static final String POST_SONG_LIST = "/api/RoomSong/song_list";//获取已点歌曲
public static final String POST_SONG = "/api/RoomSong/song";//点歌
public static final String POST_UP_SONG = "/api/RoomSong/up_song";//移动歌曲
@@ -393,9 +375,6 @@ public class Constants {
public static final String POST_CLEAR_USER_CHARM = "/api/Room/clear_user_charm";//清除魅力值
public static final String POST_MESSAGE_LIST = "/api/UserMessage/get_user_message_list";//消息列表
public static final String POST_INVITE = "/api/Guild/invite_apply_handle";//【新】受邀申请处理
public static final String GET_GROUP_INFO = "/api/Guild/get_guild_info";//群聊设置详情
public static final String POST_GROUP_INFO = "/api/Guild/set_guild_info";//设置群聊信息
public static final String GET_MEMBER_LIST = "/api/Guild/member_list";//群聊成员
public static final String POST_BIND_DETAIL = "/api/Bind/bind_detail";//绑定详情
public static final String POST_USER_WALL = "/api/User/user_gift_wall";//礼物墙
public static final String POST_USER_OLINE_STATUS = "/api/Room/user_online_status";//用户在线状态
@@ -463,12 +442,9 @@ public class Constants {
public static final String POST_DAILY_TASKS_SIGN_STATUS = "/api/Tasks/dailyTasksSignStatus";//每日签到状态
// public static final String MODIFY_MOBILE = "/api/UserData/modify_mobile";//手机换绑
public static final String MODIFY_MOBILE = "/api/UserData/modify_mobiles";//手机换绑
public static final String SET_PIT_TIME = "/api/BarRoom/set_pit_time";//房间麦位时长设置
public static final String MODIFY_MOBILE = "/api/UserData/modify_mobile";//手机换绑
public static final String BIND_MOBILE = "/api/UserData/bind_mobile";//手机绑定
public static final String GET_FESTIVAL_THEME = "/api/Theme/get_festival_theme";//节日主题接口
public static final String GET_PERSONALTY_LIST_BEAN = "/api/Decorate/get_decorate_list";//装饰列表
public static final String POST_SIGN_START = "/api/Sign/start_sign";//签约开始
@@ -478,4 +454,5 @@ public class Constants {
public static final String POST_SIGN_COIN = "/api/Sign/sign_coin";//签约出价
}

View File

@@ -23,7 +23,6 @@ import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;
import lombok.Getter;
import lombok.Setter;
import okhttp3.Call;
import okhttp3.Callback;
@@ -41,7 +40,6 @@ public class GiftAnimView extends FrameLayout implements GiftSvgaView.OnAnimatio
private ReentrantLock lock = new ReentrantLock();
private List<String> giftArray = new ArrayList<>();
@Setter
@Getter
public ExecutorService queue;
private Context mContext;
private boolean isOnece;
@@ -227,20 +225,17 @@ public class GiftAnimView extends FrameLayout implements GiftSvgaView.OnAnimatio
public void openOrCloseEffectViewWith(boolean isShow) {
this.isShow = isShow;
removeSvgaQueueData();
if(playerMp4View!=null) {
playerMp4View.stopPlay();
playerMp4View.setVisibility(View.GONE);
}
playerMp4View.stopPlay();
playerMp4View.setVisibility(View.GONE);
setVisibility(isShow ? View.VISIBLE : View.GONE);
requestLayout();
}
public void stopPlay() {
removeSvgaQueueData();
if(playerMp4View!=null) {
playerMp4View.stopPlay();
playerMp4View.setVisibility(View.GONE);
}
playerMp4View.stopPlay();
playerMp4View.setVisibility(View.GONE);
}

View File

@@ -98,13 +98,6 @@ public class QXGiftPlayerManager {
}
public void displayFullEffectView1(List<String> stringList){
if (getDefaultFullEffectView().getQueue() == null){
// 创建专用线程池替代GCD队列
ExecutorService queue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
Executors.defaultThreadFactory());
fullEffectView.setQueue(queue);
}
getDefaultFullEffectView().displayEffectView1(stringList);
}

View File

@@ -74,7 +74,7 @@ public class RoomKtvWheatView extends BaseWheatView {
sex = bean.getSex();
if (isOn()) {
//开启声浪
if (mIvRipple != null) {
if (mCharmView != null) {
mIvRipple.stopAnimation(true);
mIvRipple.setVisibility(VISIBLE);
}
@@ -103,7 +103,12 @@ public class RoomKtvWheatView extends BaseWheatView {
mIvTagBoss.setVisibility(VISIBLE);
ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
} else {
// mIvTagBoss.setVisibility(GONE);
// @DrawableRes int origin = getOriginImage();
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo :
// (origin == 0 ? R.mipmap.room_ic_wheat_default : origin), mRiv);
mRiv.setImageResource(bean.getIs_lock() == 1 ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default);
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
}
if (isMute()) {
ImageUtils.loadRes(R.mipmap.room_microphone_off, mIvSex);

View File

@@ -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("mic.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());
}
}

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<stroke
android:width="1dp"
android:color="@color/divider" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
</shape>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="360"
android:endColor="#ff093a1f"
android:startColor="#ff1e4853"
android:type="linear"
android:useLevel="true" />
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="14dp"
android:topRightRadius="14dp" />
</shape>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/divider" />
<item android:state_enabled="false" android:drawable="@color/divider" />
<item android:drawable="@android:color/white" />
</selector>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="0.5dp"/>
<solid android:color="@color/divider"/>
</shape>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/za_maiw_b" />
<item>
<inset android:insetLeft="10dp">
<bitmap
android:gravity="start"
android:src="@mipmap/jinb" />
</inset>
</item>
</layer-list>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 设置渐变效果100%黑色 -> 50%黑色 -> 13%黑色 -->
<gradient
android:startColor="#FF000000"
android:centerColor="#40FFFFFF"
android:endColor="#FF212121"
android:angle="0" />
<!-- 设置白色边框 -->
<!-- <stroke-->
<!-- android:width="0.1dp"-->
<!-- android:color="#FFFFFF" />-->
<!-- 设置圆角,只设置左上和左下 -->
<corners
android:topLeftRadius="@dimen/dp_100"
android:bottomLeftRadius="@dimen/dp_100"
android:topRightRadius="0dp"
android:bottomRightRadius="0dp" />
</shape>

View File

@@ -67,8 +67,7 @@
app:layout_constraintStart_toEndOf="@+id/textView1"
app:layout_constraintTop_toTopOf="@+id/textView1"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.2"
android:visibility="gone" />
app:layout_constraintWidth_percent="0.2" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.scwang.smartrefresh.layout.SmartRefreshLayout

View File

@@ -54,8 +54,7 @@
android:gravity="center"
android:text="抽奖榜单"
android:textColor="@drawable/text_color_radio_selector"
android:textSize="@dimen/sp_14"
android:visibility="gone"/>
android:textSize="@dimen/sp_14" />
<RadioButton

View File

@@ -217,46 +217,6 @@
android:textSize="@dimen/sp_14"
app:layout_constraintBottom_toBottomOf="parent"
/>
<LinearLayout
android:id="@+id/ll_agreement"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tv_payment"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginVertical="@dimen/dp_10"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:orientation="horizontal">
<CheckBox
android:id="@+id/cb_privacy"
android:layout_width="@dimen/dp_15"
android:layout_height="@dimen/dp_15"
android:layout_marginEnd="@dimen/dp_5"
android:checked="false"
android:background="@drawable/selector_login_agreement"
android:button="@null" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我已阅读并同意"
android:textColor="@color/color_FFA8A8A8"
android:textSize="@dimen/sp_11"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_czxy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="《充值协议》"
android:textColor="#22BB79"
android:textSize="@dimen/sp_11"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -439,8 +439,7 @@
android:textSize="@dimen/sp_10"
app:layout_constraintBottom_toBottomOf="@+id/exchange_layout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/exchange_layout"
android:visibility="gone"/>
app:layout_constraintTop_toTopOf="@+id/exchange_layout" />
<View
android:id="@+id/v_checkbox"
@@ -451,8 +450,7 @@
android:focusable="false"
app:layout_constraintBottom_toBottomOf="@+id/exchange_layout"
app:layout_constraintEnd_toStartOf="@+id/tv_option"
app:layout_constraintTop_toTopOf="@+id/exchange_layout"
android:visibility="gone"/>
app:layout_constraintTop_toTopOf="@+id/exchange_layout" />
<LinearLayout
android:id="@+id/exchange_layout"
@@ -546,7 +544,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_3"
android:gravity="center"
android:text="抽次"
android:text="抽次"
android:textSize="@dimen/sp_12" />
<TextView
@@ -575,7 +573,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_3"
android:gravity="center"
android:text="抽次"
android:text="抽次"
android:textSize="@dimen/sp_12" />
<TextView

View File

@@ -122,10 +122,8 @@
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginTop="14dp"
tools:text="为什么会有这篇文章呢,是因为之前关于 TabLayout 的使用陆陆续续也写了好几篇了,感觉比较分散,且不成体系,写这篇文章的目的就是希望能把各种效果的实现一次性讲齐,所以也有了标题的「看这篇就够了」。
TabLayout作为导航组件来说使用场景非常的多也意味着要满足各种各样的需求。
在效果实现上,有同学会选择自定义 View 来做,定制性高,但易用性、稳定性、维护性不敢保证,使用官方组件能避免这些不确定性,一是开源,有很多大佬共建,会不停的迭代;二是经过大型 app 验证,比如 google play有了这两点基本可以放心大胆的使用官方组件了。
那可能有的同学又会说,道理我都懂,可是不满足需求啊,只能自定义了。是的,早期的 api 确实不够丰富,在某些需求的实现上显得捉襟见肘,但是 google 也在不断的迭代,目前为止,常见的样式都能满足。"
android:ellipsize="end"
android:maxLines="7"
android:textColor="@color/black"
android:textSize="14sp"
/>

View File

@@ -6,7 +6,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginStart="@dimen/dp_17"
android:layout_marginEnd="@dimen/dp_15"
android:layout_marginEnd="@dimen/dp_15"
android:orientation="horizontal">
<!-- 用户头像 -->
@@ -31,15 +31,14 @@
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_7"
android:layout_marginStart="@dimen/dp_7"
android:layout_marginTop="@dimen/dp_7"
tools:text="我是评论我是评论我是评论我是评论我是评论我是评论我是评论我是评论我是评论我是评论"
tools:text="我是评论"
android:textColor="@color/color_FF333333"
android:textSize="@dimen/sp_14"
app:layout_constraintStart_toStartOf="@+id/tv_nickname"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_avatar"
app:layout_constraintTop_toBottomOf="@+id/tv_nickname" />
<TextView

View File

@@ -77,7 +77,7 @@
android:layout_gravity="center_horizontal"
android:background="@mipmap/text_bj"
android:gravity="center"
tools:text="x30"
android:text="x30"
android:textColor="@color/color_FF333333"
android:textSize="@dimen/sp_10"
android:visibility="gone"
@@ -88,8 +88,8 @@
<ImageView
android:id="@+id/im_heartssss"
android:layout_width="@dimen/dp_36"
android:layout_height="@dimen/dp_17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:src="@mipmap/icon_heart"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -2,52 +2,45 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/dp_316"
android:layout_height="wrap_content">
android:layout_height="@dimen/dp_50">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="@dimen/dp_50"
android:scaleType="fitXY"
android:src="@mipmap/gift_p_b"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="0dp"
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginStart="60dp"
android:layout_marginEnd="@dimen/dp_2"
android:paddingVertical="@dimen/dp_5"
android:orientation="horizontal"
android:ellipsize="start"
android:maxLines="1"
android:text="礼品"
android:textColor="#FFDE77"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/iv_piaoping"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_2"
android:ellipsize="start"
android:maxLines="2"
android:text="礼品"
android:textColor="#FFDE77"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_to_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_8"
android:text="...."
android:textColor="#FFDE77"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_to_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_8"
android:text="...."
android:textColor="#FFDE77"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_name"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_piaoping"

View File

@@ -43,17 +43,19 @@
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.6" />
app:layout_constraintGuide_percent="0.62" />
<ImageView
android:id="@+id/iv_frame_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:contentDescription="@null"
android:scaleType="fitXY"
app:layout_constraintHeight_default="spread"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintWidth_default="spread"
tools:src="@mipmap/me_sj"/>
tools:src="@mipmap/me_sj"
android:visibility="gone"/>
<ImageView
android:id="@+id/iv_sex"

View File

@@ -24,6 +24,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
android:src="@mipmap/jiaoy"/>
<!-- 头像框,与头像大小相同,覆盖在头像上 -->
@@ -46,12 +47,13 @@
android:id="@+id/iv_ripple"
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
app:autoPlay="false"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintBottom_toBottomOf="@id/riv"
app:layout_constraintEnd_toEndOf="@id/riv"
app:layout_constraintStart_toStartOf="@id/riv"
app:layout_constraintTop_toTopOf="@id/riv"
app:layout_constraintDimensionRatio="1:1"
app:loopCount="0"
app:source="mic.svga" />

View File

@@ -10,6 +10,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- <com.opensource.svgaplayer.SVGAImageView-->
<!-- android:id="@+id/image"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="0dp"-->
<!-- android:scaleType="fitCenter"-->
<!-- app:autoPlay="true"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:loopCount="1" />-->
<com.tencent.qgame.animplayer.AnimView
android:id="@+id/play_view"
android:layout_width="0dp"
@@ -17,6 +29,8 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:divider="@drawable/divider"
android:background="@drawable/bg_amount_layout"
android:showDividers="middle"
android:orientation="horizontal">
<Button
android:id="@+id/btnDecrease"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:background="@drawable/btn_amount"
android:text="-"/>
<EditText
android:id="@+id/etAmount"
android:layout_width="0dp"
android:layout_height="match_parent"
android:minWidth="60dp"
android:layout_weight="2"
android:background="@null"
android:inputType="number"
android:gravity="center"
android:text="1"/>
<Button
android:id="@+id/btnIncrease"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:background="@drawable/btn_amount"
android:text="+"/>
</LinearLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

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