243 Commits

Author SHA1 Message Date
1669932feb 1:修改上架出现的问题 2026-03-10 10:38:32 +08:00
lzl
be4356f317 潘多拉魔盒再次抽奖判断空。 2026-01-30 19:14:23 +08:00
9c7567dfd1 1:修改爱豆计划名称,变更成潘多拉魔盒
2:修改搜索,只有点击确定才可以搜索
2026-01-30 16:10:08 +08:00
88ce3ac161 1:修改马迎新春的弹框提示,展示背景 2026-01-30 14:25:45 +08:00
48506a075e 1:修改马迎新春打开不关闭房间设置 2026-01-30 10:09:24 +08:00
lzl
cb79afaab6 注销许愿卡,爱豆计划记录闪退,默认主题内页黑色。 2026-01-30 09:47:22 +08:00
lzl
dfc64d7a14 注销许愿卡,爱豆计划记录闪退,默认主题内页黑色。 2026-01-30 09:47:15 +08:00
lzl
3977e3e158 删除错误资源 2026-01-29 19:28:51 +08:00
lzl
877862e507 爱豆计划。 2026-01-29 19:04:26 +08:00
5ce33aeeb1 1:修改马迎新春兑换
2:修改转盘抽盘展示规则的页面
2026-01-29 18:26:35 +08:00
0afb5dbbfd 1:修改马迎新春兑换 2026-01-29 17:38:21 +08:00
3530c10772 1:修改房间设置,
2:修改个人主页头像框展示
3:修改礼物墙数据错乱不让展示的问题
4:修改房间设置里面的活动,变成趣味活动,当有参数的并且是打开的情况下,是展示的
2026-01-29 17:25:23 +08:00
5b27d91278 1:添加炼仙传说功能
2:修改混淆,
2026-01-28 18:43:36 +08:00
lzl
513cc23d9c 春节主题:礼物飘屏。 2026-01-28 16:43:29 +08:00
lzl
7aa294c3a9 春节主题:首页弹窗、礼物、部分按钮。 2026-01-28 16:17:06 +08:00
lzl
88ce0205fb 春节主题:登录、主页面。 2026-01-28 09:29:03 +08:00
3d0fb12565 1:还原接收文本消息 2026-01-27 17:20:04 +08:00
lzl
cb16dbb9e1 任务幸运币UI。 2026-01-27 14:37:32 +08:00
8ce7a9e5de 1:修改进入房间后,先获取在线列表
2:修改图片展示,展示圆形图片
3:添加后台禁用后,页面弹起禁用弹框
4:修改日志,不在展示返回结果,不展示域名
2026-01-27 14:36:05 +08:00
8db507718c 1:修改所有和礼物有关系的接口,分别是打赏接口、房间礼物,这个进行修改
2:修改排麦插队礼物,id传0
3:歌单礼物传递的id是100
2026-01-26 14:18:07 +08:00
lzl
e23578838c 密码房完善:小时榜显示密码锁 3。 2026-01-26 11:49:53 +08:00
lzl
973fac58a4 密码房完善:创建房间设置密码 2。 2026-01-26 11:29:03 +08:00
lzl
8a587210cf 密码房完善1。 2026-01-26 11:20:05 +08:00
lzl
8d7de418bb 1。 2026-01-26 10:29:18 +08:00
lzl
24c4af95b4 密码房部分,幸运抽奖部分。 2026-01-26 10:27:29 +08:00
9450a351c5 1:添加热度卡,在背包显示
2:修改道具商城和个性装扮,分别显示热身卡和不显示
3:完成热度卡在房间中使用,一键全使用和单个使用,完成
2026-01-26 09:40:23 +08:00
9f8f8137d1 1:修改网络初始化的时候,放在点击了弹框后在进行
2:添加礼物墙展示用户信息功能
2026-01-23 11:48:44 +08:00
lzl
d07ca522ab 跟随闪退,cp动画开始显示头像。 2026-01-23 09:40:08 +08:00
08c51e0273 1:修改营业时间,结束时间秒更改为00
2:修改在退出登录的时候,不在清除本地缓存数据
2026-01-22 16:48:16 +08:00
lzl
60b8e901b5 1。 2026-01-22 15:28:44 +08:00
lzl
885d6b1e7d 头像框清除上次资源 mIvFrame.release() 去除,用户首页头像框更新。 2026-01-22 14:52:51 +08:00
lzl
3f2989664c 头像框清除上次资源 mIvFrame.release()。 2026-01-22 10:29:49 +08:00
lzl
76f499f022 pk头像框小修改,cp动画不出来头像动画最多10次,pk切换房间刷新UI。 2026-01-22 10:18:41 +08:00
1048b8f46e 1:发布版本 2026-01-21 15:49:56 +08:00
78f290eef8 1:修改搜索房间历史,添加删除功能
2:修改图片展示添加日志记录
3:更改设置群管理员的提示语
2026-01-21 12:46:32 +08:00
lzl
3f49cf3790 cp挂件头像显示位置null判断,去除请求头打印。 2026-01-21 10:11:23 +08:00
9ab1f171f8 1:修改pk上麦的时候,进行换麦后,原还展示星光
2:修改设置房间营业时间,回显的问题
2026-01-21 09:24:58 +08:00
4e8058f200 1:在房间设置的时候,展示营业时间
2:修改选择时间展示选择的日期
3:修改了群组全成员展示接界面
2026-01-20 21:15:23 +08:00
4fdd5578a8 1:修改时间选择框,根据需要,展示时分秒和不显示时分秒
2:修改展示设备id,在头部信息中,使用第三方的获取设备唯一id
3:优化群聊成员列表展示
4:修改房间封面,上传图片的时候,需要裁剪
5:添加营业时间展示
6:pk修改开始的时候,选择时间去掉1分钟
7:修改声网,添加声卡开关
2026-01-20 19:21:56 +08:00
163340a691 1:修改时间选择框,根据需要,展示时分秒和不显示时分秒
2:修改展示设备id,在头部信息中,使用第三方的获取设备唯一id
3:优化群聊成员列表展示
4:修改房间封面,上传图片的时候,需要裁剪
5:添加营业时间展示
6:pk修改开始的时候,选择时间去掉1分钟
7:修改声网,添加声卡开关
2026-01-20 19:20:06 +08:00
lzl
bf609a3964 从消息页面跟随过去房间,最小化失败。 2026-01-19 17:58:42 +08:00
lzl
e6232f5aa2 网络请求头添加版本信息 1。 2026-01-17 16:47:19 +08:00
0ae0cff87a 1:修改巡乐会榜单展示 2026-01-17 16:46:19 +08:00
lzl
ac7a3b1325 酒吧房小黑屋麦标显示,网络请求头添加版本信息。 2026-01-17 16:29:39 +08:00
16bd6d7e1a 1:修改送盲盒的时候,接口修改,需要传递gift_bag_id
2:装扮详情修改优化
2026-01-17 16:28:20 +08:00
lzl
838a2ec64a Merge remote-tracking branch 'origin/branch_new' into branch_new 2026-01-17 01:09:39 +08:00
lzl
87782e9caa fix bugs2. 2026-01-17 01:09:30 +08:00
0a0875fb88 1:修改巡乐会榜单展示 2026-01-17 01:09:27 +08:00
lzl
725add62ac fix bugs. 2026-01-17 01:08:24 +08:00
lzl
59b48e0b0f 测试 2026-01-17 00:32:39 +08:00
lzl
e5f77b626e 混淆log不打印。 2026-01-17 00:12:14 +08:00
99b3350329 1:修改酒吧房自动退出房间后,麦的状态没有更改 2026-01-16 23:33:21 +08:00
883a96f2c7 1:修改钻石收支出现来回切换出现数据重复的情况 2026-01-16 22:47:09 +08:00
lzl
8e86ba68d0 小黑屋主动退出逻辑。 2026-01-16 18:17:02 +08:00
bf507a6264 1:优化小黑屋退出房间后加入大房间 -2 2026-01-16 18:06:06 +08:00
716cafc62b 1:优化小黑屋退出房间后加入大房间 2026-01-16 17:55:18 +08:00
267b8a0aea 1:修改房间清空消息,只清空大房间消息,不清除小黑屋的消息 2026-01-16 16:31:02 +08:00
lzl
60fff84aaf Merge remote-tracking branch 'origin/branch_new' into branch_new 2026-01-16 16:05:17 +08:00
lzl
0a968babef 房间公平消息收不到。 2026-01-16 16:05:10 +08:00
b3c1ae647d 1:购买装扮的时候,默认选择的对应的天数,(后台也修改了,是可以使用的)
2:修改当在小黑屋收到大房间清空消息的推送的时候,不进行清除小黑屋的消息
2026-01-16 16:04:34 +08:00
lzl
fcc690db64 子爵公屏聊天名字颜色。 2026-01-16 09:21:09 +08:00
lzl
476de595da bg闪退问题修改. 2026-01-15 05:34:06 +08:00
lzl
a4c21485a2 闪退问题修改. 2026-01-15 05:16:06 +08:00
e24f217ab4 1:添加一键登录 2026-01-15 05:06:16 +08:00
a07ee5cfe9 1:修改酒吧房小黑屋展示的金币余额视图 2026-01-14 20:52:55 +08:00
lzl
60c97447dd Merge remote-tracking branch 'origin/branch_new' into branch_new 2026-01-14 20:28:58 +08:00
lzl
b201787513 酒吧房小黑屋禁止播放cp and jia_jia. 2026-01-14 20:28:54 +08:00
064338e838 1:给酒吧房小黑屋添加充值和显示金币的控件 2026-01-14 20:25:54 +08:00
lzl
0a0771d5a3 酒吧交友房送礼物。 2026-01-14 19:46:45 +08:00
f82e5c8348 1:修改在帮助中,使用平台的客服功能,如果对方是客服,自己不用充值可以聊天 2026-01-14 19:14:30 +08:00
d7a27baf5c 1:修改pk中,设置的pk按钮 is_pk=1:是接受pk。2:是不接受pk 2026-01-14 16:34:52 +08:00
lzl
a3551e2e33 用戶房間個人主頁跟隨bug. 2026-01-14 16:04:56 +08:00
a1fcc56551 1:修改巡乐会出现当服务端返回失败的时候,页面不能再点击的情况 2026-01-14 15:31:58 +08:00
cdb5f9b794 1:修改房间送礼弹框,设置了展示的高度是自适应
2:修改一键赠送背包礼物多次点击的时候出现的错误
2026-01-14 15:17:12 +08:00
lzl
e9ab535b2d 优化switchMic 2026-01-14 15:09:18 +08:00
lzl
f5b4dde3c6 优化roomBtnShowIsHide 2026-01-14 14:52:35 +08:00
f4f27c2c94 1:在充值的地方,添加充值协议提示 2026-01-14 10:34:54 +08:00
268c3cdd98 1:在酒吧房小黑屋中,点击送礼添加二次弹窗,并且在点击退出房间的时候,添加二次弹框确认 2026-01-14 10:09:45 +08:00
dde6ccd578 1:还原消息展示, 2026-01-13 20:12:39 +08:00
f01d903d2f 1:还原消息展示 2026-01-13 20:09:34 +08:00
e3bad8ddab 1:修改红包声音和转盘声音,变成0.04
2:修改消息列表展示的时候,展示的事200条,清除的时候,清除前100条
2026-01-13 19:59:17 +08:00
lzl
2b29b0de18 小黑屋退出上麦显示图标不对。 2026-01-13 19:39:33 +08:00
6e5e8abc0b 1:特效图片 2026-01-13 19:14:26 +08:00
38d1c266d6 1:修改进入小黑屋添加了和外部的特效一个功能
2:给用户主页添加私信按钮,常显示
3:优化退出酒吧房小黑屋,
2026-01-13 19:13:19 +08:00
lzl
6a22259c16 除Main跳转Room,其他全部finish。 2026-01-13 18:41:12 +08:00
lzl
b1523c2f2a 交友小黑屋礼物价格1,酒吧房性别,vap mp4播放声音设置0.04f。 2026-01-13 16:07:28 +08:00
8f4c2d1b83 1:优化服务地址
2:修改盲盒转盘声音,修改成0.2
3:修改红包声音,0.2
4:修改巡乐会,最后出现的空白
5:优化一键赠送背包礼物的时候,连续点击后,出现的错误
7:修改打包的应用图标
2026-01-13 16:04:21 +08:00
lzl
0fd8ecd73d 交友小黑屋礼物价格。 2026-01-13 14:32:24 +08:00
6b87252a51 1:优化服务地址 2026-01-13 10:02:09 +08:00
64ced88287 1:修改转盘去掉了特效还又声音
2:修改巡乐会去掉跳过动画,
3:修改巡乐会结果页面,进行展示,不在关联抽奖
2026-01-13 09:39:28 +08:00
lzl
716f292fa5 拍卖房麦位只有前六个能说话。 2026-01-12 17:40:32 +08:00
lzl
39b9ea73a1 优化麦圈显示延迟,拍卖房麦位丢失。 2026-01-12 17:06:07 +08:00
c67b07e3b9 1:添加练歌房,已点歌曲搜索(只能搜索用户id)、删除功能 2026-01-12 15:40:51 +08:00
lzl
5a1edb6c4a 酒吧交友房 进出房间不接受Im消息,用户详情 标签显示优化。 2026-01-12 09:55:37 +08:00
a034e5e954 1:修改使用Glide,原设置了尺寸,出现页面显示缓慢的情况,现在禁止了设置图片的大小,使用RGB_565,减少内存占用 2026-01-12 09:47:06 +08:00
15ed708853 1:修改道具商城展示用户头像
2:修改房间用户展示的靓号图标展示
2026-01-09 20:15:46 +08:00
ca4d9ea20a 1:修改趣味展示的时候,出现的换行和里面展示的时候,出现挤压了
2:修改昵称在输入的时候,不能输入空或者制表符等
2026-01-09 16:46:34 +08:00
84fa4ed1f3 1:修改酒吧房小黑屋不显示头条、任务和巡乐会
2:修改连点送盲盒报错
2026-01-09 15:45:59 +08:00
lzl
4c7a2ae3b7 酒吧交友房 getGiftList 防止越界 2。 2026-01-09 15:27:24 +08:00
34f4d980ad 1:修改酒吧房小黑屋礼物 2026-01-09 14:38:00 +08:00
lzl
2589b97f29 酒吧交友房 getGiftList 防止越界。 2026-01-09 14:35:44 +08:00
5946cf97b9 1:修改酒吧房主动调用下麦的操作
2:修改房间明细,只有自己创建的,添加了时间对应的收益和流水,我主持的知悉那是时间
2026-01-09 14:18:43 +08:00
lzl
0be33ec918 酒吧交友房 消息显示 4。 2026-01-09 14:12:39 +08:00
lzl
8264974d85 酒吧交友房 消息显示 3。 2026-01-09 12:48:44 +08:00
lzl
54b3312eac 酒吧交友房 消息接收重置 2。 2026-01-09 11:57:43 +08:00
lzl
0ff889d72a 酒吧交友房 消息接受重置。 2026-01-09 11:42:42 +08:00
lzl
7436649f71 酒吧外部送礼物拦截1。 2026-01-09 11:36:00 +08:00
lzl
ea85b71e2f 酒吧外部送礼物拦截。 2026-01-09 11:21:58 +08:00
lzl
58c39962fa 酒吧交友房 数据更新2。 2026-01-09 11:10:17 +08:00
lzl
36fbc88f21 酒吧交友房 数据更新。 2026-01-09 11:03:12 +08:00
97f30ce233 1:修改酒吧房不显示清除魅力按钮 2026-01-09 09:45:14 +08:00
lzl
c355fd66d6 酒吧交友房 定时器。 2026-01-09 09:44:31 +08:00
lzl
2e61fa5e4d 酒吧交友房 消息显示。 2026-01-09 09:38:42 +08:00
lzl
b5fcf232fe 酒吧交友房 消息接收多条。 2026-01-08 19:41:30 +08:00
lzl
9627a476f7 酒吧交友房 消息高亮显示。 2026-01-08 19:30:21 +08:00
lzl
d5cbb5008c 酒吧交友房 聊天消息。 2026-01-08 19:10:48 +08:00
lzl
1b560a3806 酒吧交友房聊天。 2026-01-08 18:59:20 +08:00
34552f45ec 1:修改换麦带着自定义礼物 2026-01-08 18:41:07 +08:00
lzl
ab228eb05d 定时器 2026-01-08 18:39:31 +08:00
lzl
a8328ac8b9 消息 2026-01-08 18:29:45 +08:00
lzl
d2f2829ca2 UI 1039 endtime 2 2026-01-08 17:31:06 +08:00
lzl
43600c60c0 UI 1039 endtime 2026-01-08 17:27:19 +08:00
lzl
e12bb36fe5 UI 优化。 2026-01-08 17:24:52 +08:00
lzl
e74bfde545 退出房间 2026-01-08 17:02:29 +08:00
0b37364a11 1:添加酒吧房抱麦推送,在推送过来后,需要选择礼物
2:添加酒吧房设置了自定义礼物推送
3:修改自定义礼物设置的接口,传递了roomId,用于推送消息
2026-01-08 15:36:17 +08:00
lzl
ac09992b01 messageEx 2026-01-08 14:09:20 +08:00
26a40f8ffb 1:添加实名认证的时候,身份证号前后输入空格,出现的不能实名的情况
2:修改一键全撩的时候,麦上只有自己的时候,就给提示
3:添加酒吧房进入交友房,双方下麦,在麦上的下麦,
2026-01-08 11:43:30 +08:00
lzl
a8ae4a61c2 小黑屋 填充数据。 2026-01-08 11:18:42 +08:00
fe78c968f2 1:添加交友小屋接口
2:修改上下麦展示设置时长的问题
3:修改上主持麦出现选择礼物的弹框
4:添加上嘉宾麦的判断
2026-01-07 20:35:23 +08:00
lzl
9fbb12819f 酒吧 撩她动画播放 and setTime 显示。 2026-01-07 19:25:34 +08:00
6338728ddf 1:修改酒吧房展示的,
2:修改约她接口
2026-01-07 19:19:28 +08:00
50d509dc12 1:添加单个撩ta数据
2:添加约她获取数据
2026-01-07 18:14:05 +08:00
lzl
1c4384f5d5 酒吧 定时器。 2026-01-07 18:03:16 +08:00
5f7bac8a12 1:添加酒吧房上麦 2026-01-07 17:13:33 +08:00
3dcdd1e599 1:修改金币钻石收支接口
2:修改进入房间添加字段
3:修改所有的图片展示,使用url作为key
2026-01-07 17:05:48 +08:00
lzl
d1cd2aeef7 优化头像框加载、麦圈加载,二卡八放到对应fragment加载。 2026-01-07 16:53:36 +08:00
b76136b604 1:修改酒吧房弹框接口调用
2:修改直播间送礼接口
2026-01-07 09:01:59 +08:00
2f0f5ae5e8 1:修改酒吧房弹框接口调用 2026-01-06 15:08:39 +08:00
lzl
d48f13f266 酒吧房 交友小屋 UI 2026-01-06 14:43:12 +08:00
5cc393fe06 1:添加酒吧房的弹框获取数据 2026-01-06 09:37:44 +08:00
44ebb14fb3 1:添加酒吧房各个弹框,只有界面 2026-01-05 16:17:04 +08:00
lzl
9ef4f27ed9 酒吧房 1 2026-01-05 15:43:25 +08:00
43ea35d3a2 1:修改道具商城,当没有banner的时候,出现报错的问题 2026-01-04 18:38:48 +08:00
3efe9c9146 1:将道具商城做成原生的,添加点击的时候展示动效 2026-01-04 17:59:52 +08:00
lzl
b473751913 切换账号登录MQTT未连接修改。 2026-01-04 16:44:49 +08:00
lzl
0e830e411a 多次最小化无法返回问题修改,MainActivity 竖屏显示。互娱房高度340->370 2026-01-04 11:16:31 +08:00
5d17bf8de0 1:修改重复strings 2026-01-04 10:46:55 +08:00
f77b5ba4d7 1:修改系统和官方公告展示html出现标签展示的问题
2:添加群全员禁言和单个禁言的功能
3:将道具商城做成原生的
4:添加应用更新的时候,添加版本判断和重新刷新手机文本,预防出现安装缓存(自己测试十几次,未在出现问题,还需要大量测试)
2026-01-04 08:58:09 +08:00
aa96aa4a3b 1:修改超时时间30秒
2:练歌房已点歌曲,添加展示用户code,
3:修改练歌房已点歌曲展示视图
4:练歌房已点歌曲添加删除功能(接口已经接入,但是隐藏了)
5:修改辅服务器
2025-12-31 16:35:13 +08:00
lzl
8bd22ae41a 小黑屋闪退没有房主信息。 2025-12-31 16:33:09 +08:00
lzl
510aa804ab 82 练歌bean混淆问题。 2025-12-31 10:44:22 +08:00
c2fd1df529 1:添加备用服务器,在请求themeData的时候,返回的不对的时候,就切换服务器 2025-12-31 03:31:31 +08:00
lzl
479e039e56 82 youhua. 2025-12-30 20:02:39 +08:00
9126676599 1:修改获取发送红包的时机,并且添加了当接口返回code=0的时候,也能发送红包 2025-12-30 19:57:29 +08:00
7f881260aa 1:添加签到弹框,当没有签到的时候,进入应用60秒弹出,当已经签到,不在弹框,添加结束清除定时器 2025-12-30 19:22:39 +08:00
lzl
3f1b8ee2fa 82 添加签到延迟1分钟弹出。 2025-12-30 19:05:23 +08:00
7b6be82c54 1:修改红包提示语添加括号 2025-12-30 18:47:13 +08:00
aab29ea784 1:修改点唱房歌手头像转圈
2:修改主题展示
3:修改动态详情
2025-12-30 18:43:00 +08:00
ab556d2519 1:添加元旦主题,添加新的接口 2025-12-30 14:16:03 +08:00
lzl
4f48c55cf6 82 消息背景透明色 1 2025-12-30 14:13:16 +08:00
lzl
359f93aac7 82 fix bugs,消息背景透明色,混淆mapping详细规则。 2025-12-30 14:10:35 +08:00
lzl
e6892d533c 82 fix bugs,网络请求timeout=30。隐藏init chat failed 弹窗。 2025-12-29 22:29:01 +08:00
lzl
67c56b2d4f 82 入场特效播放容错,网络请求timeout=10。 2025-12-29 09:51:27 +08:00
lzl
fa6f40c369 82 2025-12-26 19:41:52 +08:00
lzl
9476655ba3 房间内按钮礼物显示异常优化 2025-12-25 21:30:14 +08:00
lzl
27485de14f 最小化进入房间and拍卖房得到主持权限 添加log. 2025-12-25 19:41:49 +08:00
d6efdefc99 1:修改最小化进入房间后,麦克风状态变化 2025-12-25 18:40:41 +08:00
8b24d3ace5 1:修改红包文字错误 2025-12-25 16:45:53 +08:00
730b94cff5 1:修改礼物展示幸运币的简介 2025-12-25 16:00:30 +08:00
lzl
e3751528ad 一键登录 loading hide 2 2025-12-25 15:31:49 +08:00
lzl
ff9677fa6d 一键登录 loading hide 1 2025-12-25 15:28:20 +08:00
lzl
be2306b50c 一键登录 loading hide,fix bug 2025-12-25 15:27:17 +08:00
2adc4948c7 1:修改启动页播放视频 2025-12-25 15:05:46 +08:00
6b1614d768 1:修改启动页播放视频 2025-12-25 14:54:34 +08:00
8fec498dba 1:还原代码 2025-12-25 14:48:31 +08:00
e26101c35f 1:修改登录出现来回跳 2025-12-25 11:48:11 +08:00
bb31bafa55 1:修改练歌房点歌后,某些歌曲返回的类型错误,
2:修改启动页播放视频,黑屏后直接跳过播放
3:修改退出关闭mqtt
4:修改进入应用,会在登录页面和编辑页面弹起弹框和推荐的问题
5:修改房间,在推送了礼物后,多次判断是否布局打开
2025-12-25 10:31:47 +08:00
826469178e 1:修改互娱房,麦上用户发生变化后,出现点击礼物的时候,没有在麦上的展示出来了
2:修改互娱房换麦不显示离线问题
2025-12-24 19:48:17 +08:00
addd97a434 修改互娱房,麦上用户发生变化后,出现点击礼物的时候,没有在麦上的展示出来了 2025-12-24 18:50:02 +08:00
lzl
84fb05044a 优化麦圈,泄漏处理 2025-12-24 18:33:06 +08:00
342cfd347c 1:修改所有接口返回提示,只是添加了返回错误的提示,不涉及功能
2:给所有网络请求添加网络判断,添加拦截器
3:启动页添加启动视频,添加跳过功能
4:去掉抱麦弹框,直接跳转到用户列表
5:修改拍卖房,当抱人上麦后,没有选择关系,然后退出房间再次进来后,显示立即竞拍的按钮
6:修改我的歌单,添加和修改的时候,选择了不能使用的礼物,让dialog不关闭
7:修改点唱房,点一个人同一首歌,右侧下一首歌的作者不显示的问题
8:修改互娱房,选择关系的时候,会出现两次选择关系的问题
9:修改在送背包礼物的时候,最后一个送出,页面没有刷新
10:修改房间设置里面,点击了抽盘,设置页面不关闭的问题
11:修改个性装扮中,购买的装扮展示的时候,出现图片裁剪
2025-12-24 17:52:26 +08:00
lzl
214c339e93 强更替换为appUpdate库。 2025-12-23 18:20:25 +08:00
bb54407c62 1:修改点唱房切歌 2025-12-23 05:51:57 +08:00
lzl
c22e88eebb fix bugs 2. 2025-12-23 04:18:24 +08:00
lzl
0444a906ba fix bugs 1. 2025-12-23 03:48:19 +08:00
lzl
e4ed3eb9a1 fix bugs. 2025-12-23 03:14:01 +08:00
eee16d3a4a 修改进入房间提示 2025-12-23 01:39:32 +08:00
lzl
e3d4240a82 爵位显示拉伸。 2025-12-23 01:15:54 +08:00
b7320cb51a 1:修改清除魅力报错
2:修改进入房间请求接口出现错误,login没有消失
2025-12-23 00:44:52 +08:00
4a83bbda2d 1:修改已点歌曲,这里如果服务端发送的值存在重复,就重复了 2025-12-23 00:13:40 +08:00
f0451bfeea 1:修改进场特效展示
2:修改已点歌曲展示列表刷新
2025-12-23 00:09:33 +08:00
lzl
7e6d174297 77 fix bugs. 2025-12-22 23:19:16 +08:00
8b24ac310e 1:只是启动页动画
2:修改房间消息,插入动画
2025-12-22 23:06:17 +08:00
9bf2de01d4 1:修改礼物飘屏判断送的人和接收的人
2:修改所有盘在次点击的时候,初始化选中状态
3:修改礼物飘屏的文字大小
4:修改首页去围观展示的文字
2025-12-22 22:30:34 +08:00
lzl
c7018cce42 Merge remote-tracking branch 'origin/branch_new' into branch_new 2025-12-22 19:19:09 +08:00
lzl
320f742b87 77 拍卖房闪退。 2025-12-22 19:18:58 +08:00
ec2e754806 1:修改房间设置功能 2025-12-22 18:40:57 +08:00
lzl
daba3d9872 77 红包 bug修改。 2025-12-22 18:32:11 +08:00
lzl
435d2084d1 77 红包 bug修改。 2025-12-22 16:46:54 +08:00
e3744843d9 1:修改幸运值总流水展示 2025-12-22 15:30:47 +08:00
9774b0bb2c 1:修改暴币展示飘屏换行 2025-12-22 15:24:26 +08:00
lzl
ed7632c142 77 每日任务根据id判断是师傅还是cp 2025-12-22 14:30:32 +08:00
f5287becee 1:添加更换设置服务器地址
2:添加关闭红包声音图标
2025-12-22 14:04:19 +08:00
lzl
e21345ba61 77 3秒 2025-12-22 11:25:31 +08:00
lzl
ca3580ad28 77 加入房间前判断上一个房间是否游戏中,日志上传后删除之前的日志数据。 2025-12-22 11:04:53 +08:00
837231f4f0 1:修改送礼中趣味的岁月之城和时空之巅,不需要选择人员就可以打开
2:优化用在房间点击用户,点击抱麦出现的错误
3: 在岁月之城和时空之巅中查看记录的时候,进行判断,当返回的nickname是null的时候,就直接不展示赠与
4:修改任务UI,
5:添加房间暴币功能
6:修改房间暴币飘屏
7:添加启动页动画
8:修改房间的设置
2025-12-22 09:02:42 +08:00
53b9f0f034 1:修改送礼中趣味的岁月之城和时空之巅,不需要选择人员就可以打开
2:优化用在房间点击用户,点击抱麦出现的错误
3: 在岁月之城和时空之巅中查看记录的时候,进行判断,当返回的nickname是null的时候,就直接不展示赠与
4:修改任务UI,
5:添加房间暴币功能
6:修改房间暴币飘屏
7:添加启动页动画
8:修改房间的设置
2025-12-22 09:02:22 +08:00
f34a67c2e8 Merge remote-tracking branch 'origin/branch_new' into branch_new 2025-12-19 18:42:30 +08:00
6bd210217a 1:修改手机换绑倒计时添加管理类 2025-12-19 18:41:29 +08:00
lzl
6c8065711d 77 红包闪退,红包可以1=1, 2025-12-19 18:41:16 +08:00
lzl
5c607c58ae 77 签约房内切换初始化数据,红包闪退 2025-12-19 15:54:08 +08:00
f2363dad01 1:修改巡乐会抽奖次数,更改为1-5-8
2:修改手机换绑和手机绑定
3:修改系统消息展示背景
2025-12-19 15:52:22 +08:00
07dbffaa5a 1:修改巡乐会抽奖次数,更改为1-5-8
2:修改手机换绑和手机绑定
3:修改系统消息展示背景
2025-12-19 15:51:24 +08:00
lzl
b028ec883b 77 签约房开始webp动画根据屏幕尺寸走 2025-12-19 11:45:35 +08:00
lzl
552e238254 77 签约房开始webp动画,练歌房右侧麦上用户刷新。 2025-12-19 11:27:42 +08:00
3fde4df00f 1:修改去上一个房间出现的im未连接的问题
2:修改房间点击用户主页更改pitnumber判断问题
2025-12-19 09:23:05 +08:00
lzl
471a0453fa 77 pk隐藏 2025-12-18 19:06:17 +08:00
lzl
420afc7a1e 77 练歌房 演唱者麦 2025-12-18 17:10:38 +08:00
6130accb48 1:修改房间排行榜头像图、小时榜背景图 2025-12-18 17:02:54 +08:00
e2b0c9ce8c 1:修改获取验证码,当返回后才会更新页面(两个地方没有修改:1:提现的二次确认和注销的二次确认) 2025-12-18 15:53:48 +08:00
lzl
894b397537 77 优化签约房按钮 2025-12-18 14:24:09 +08:00
lzl
6207705d2a 77 fix bugs. 2025-12-18 11:17:51 +08:00
lzl
f5fea27595 Merge remote-tracking branch 'origin/branch_new' into branch_new 2025-12-18 10:33:17 +08:00
lzl
c388d765d4 77 交友房上麦 2025-12-18 10:33:00 +08:00
952621baaa 1:添加cos的混淆规则 2025-12-18 10:28:46 +08:00
lzl
df499aaa6c 77 优化任务领取,log存储data/data/ 2025-12-17 19:22:14 +08:00
3d8e152cd8 1:修改mqtt链接适用域名链接
2:修改粉丝列表展示按钮错误的问题
2025-12-17 19:00:37 +08:00
lzl
727e343d1f 77 优化底部按钮显示。 2025-12-17 18:59:25 +08:00
ef27636564 1:更新实名认证添加toast 2025-12-17 11:44:45 +08:00
aa778ca1de 1:修改排行榜适配
2:添加踢出房间成功toast
3:删除多余重复的图标
2025-12-17 10:55:00 +08:00
lzl
90077d24f6 77 红包非当前房间的不添加。 2025-12-17 09:31:54 +08:00
lzl
81b41ef392 77 广场列表内容显示不全and注销用户跳转个人主页 2025-12-16 18:32:46 +08:00
lzl
c2714ff68a 77 7 跳转创建房间 判断是否实名认证 2025-12-16 17:52:57 +08:00
lzl
1fbece3e62 77 7 跳转创建房间 2025-12-16 17:40:38 +08:00
lzl
7f4843b023 77 任务显示item复用修改 2025-12-16 17:32:58 +08:00
lzl
ec3f3d6233 77 任务显示优化。 2025-12-16 17:21:45 +08:00
1b06d5725f 1:修改练歌房修改调音台成0的时候,更换演唱者没有声音了 2025-12-16 17:10:04 +08:00
0874998249 1:修改家族中滑动展示问题 2025-12-16 16:15:41 +08:00
lzl
b611147176 77 2025-12-16 15:43:44 +08:00
ac9d9b19fd 1:修改歌单列表每一次获取20条 2025-12-16 15:42:29 +08:00
lzl
ea2b45c1be 切歌接口添加新参数isAutoNext 0:被动,1:自动。 2025-12-16 15:06:26 +08:00
19bc9dbad8 1:修改全部任务显示添加角标 2025-12-16 14:51:57 +08:00
lzl
4b356a6ce4 任务修改。 2025-12-16 14:44:48 +08:00
956 changed files with 31482 additions and 6736 deletions

2
.idea/.name generated
View File

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

View File

@@ -44,7 +44,6 @@ android {
kotlinOptions {
jvmTarget = '11'
}
packagingOptions {
// exclude 'lib/arm64-v8a/libagora-fdkaac.so'
}

Binary file not shown.

Binary file not shown.

View File

@@ -5,6 +5,7 @@ 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;
@@ -29,6 +30,7 @@ import com.blankj.utilcode.util.BarUtils;
import com.blankj.utilcode.util.LogUtils;
import com.hjq.toast.ToastUtils;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.base.CommonAppContext;
import com.xscm.moduleutil.dialog.LoadingDialog;
import com.xscm.moduleutil.utils.BackgroundManager;
import com.xscm.moduleutil.utils.ColorManager;
@@ -83,8 +85,10 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
@SuppressLint("UnspecifiedRegisterReceiverFlag")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
initFestivalTheme(CommonAppContext.getInstance().is_open);
super.onCreate(savedInstanceState);
getWindow().getDecorView().setBackgroundResource(R.mipmap.log_bj);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// getWindow().getDecorView().setBackgroundResource(R.attr.app_bg_img);
setContentView(getLayoutId());
doDone();
// 隐藏标题栏
@@ -103,7 +107,7 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
// 注册背景更新监听器
BackgroundManager.getInstance().addListener(this);
// 尝试加载网络背景
loadNetworkBackground();
// loadNetworkBackground();
// 注册颜色变化监听器
ColorManager.getInstance().addColorChangeListener(this);
@@ -114,6 +118,25 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
EventBus.getDefault().register(this);
}
// 节日判断+主题切换核心方法
private void initFestivalTheme(int currentFestival) {
switch (currentFestival) {
case 0:
setTheme(R.style.AppTheme_CustomAttrs);
break;
case 1:
setTheme(R.style.AppTheme_Spring_CustomAttrs);
break;
case 2:
setTheme(R.style.AppTheme_newYear_CustomAttrs);
break;
default:
// 默认皮肤
setTheme(R.style.AppTheme_CustomAttrs);
break;
}
}
// 在Activity中
private static final int REQUEST_OVERLAY_PERMISSION = 1001;
@@ -179,28 +202,8 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
protected void loadNetworkBackground() {
// 只有当已经有背景URL时才加载
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);
}
});
}
}
// int backgroundUrl = BackgroundManager.getInstance().getBackgroundUrl();
// getWindow().getDecorView().setBackgroundResource(backgroundUrl);
}
@Override
@@ -213,7 +216,7 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
// 提供一个方法供子类调用用于设置背景URL
protected void setNetworkBackgroundUrl(String url) {
BackgroundManager.getInstance().setBackgroundUrl(url);
// BackgroundManager.getInstance().setBackgroundUrl(url);
}
@Override
@@ -256,13 +259,14 @@ 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,6 +117,7 @@ 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(VISIBLE);
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);
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(VISIBLE);
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);
helper.getView(R.id.dy_content_tv).getViewTreeObserver().removeOnPreDrawListener(this);//销毁
} else {
helper.getView(R.id.dy_lookmore_tv).setVisibility(GONE);

View File

@@ -14,8 +14,11 @@ import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.bean.GiftPackBean;
import com.xscm.moduleutil.event.RoomGiftPackToEvent;
@@ -31,7 +34,7 @@ import java.util.List;
* @Time 2025年7月29日23:36:25$ $
* @Description 背包礼物适配器$
*/
public class GiftPackAdapter extends BaseAdapter {
public class GiftPackAdapter extends BaseQuickAdapter<GiftPackBean, BaseViewHolder> {
private final List<GiftPackBean> mDatas;
private final LayoutInflater inflater;
private final Context mContext;
@@ -47,6 +50,7 @@ public class GiftPackAdapter extends BaseAdapter {
private final int pageSize = 100;
public GiftPackAdapter(Context context, List<GiftPackBean> mDatas, int curIndex, String type) {
super(R.layout.item_gift_room, mDatas);
inflater = LayoutInflater.from(context);
this.mDatas = mDatas;
this.curIndex = curIndex;
@@ -60,14 +64,45 @@ public class GiftPackAdapter extends BaseAdapter {
* 如果够则直接返回每一页显示的最大条目个数pageSize,
* 如果不够,则有几项返回几,(mDatas.size() - curIndex * pageSize);(也就是最后一页的时候就显示剩余item)
*/
@Override
public int getCount() {
return mDatas.size() > (curIndex + 1) * pageSize ? pageSize : (mDatas.size() - curIndex * pageSize);
}
// @Override
// public int getCount() {
// return mDatas.size() > (curIndex + 1) * pageSize ? pageSize : (mDatas.size() - curIndex * pageSize);
// }
//
// @Override
// public GiftPackBean getItem(int position) {
// return mDatas.get(position + curIndex * pageSize);
// }
@Override
public GiftPackBean getItem(int position) {
return mDatas.get(position + curIndex * pageSize);
protected void convert(@NonNull BaseViewHolder helper, GiftPackBean giftModel) {
helper.getView(R.id.cl_gift).setOnClickListener(v -> {
// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
EventBus.getDefault().post(new RoomGiftPackToEvent(this, giftModel, 2));
});
helper.setVisible(R.id.integral, true).setText(R.id.integral, "x" + giftModel.getNum());
helper.setText(R.id.tv_gift_name, giftModel.getGift_name());
//设置礼物价格
String surplusTxt = giftModel.getGift_price();
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(surplusTxt);
//ForegroundColorSpan 为文字前景色BackgroundColorSpan为文字背景色
ForegroundColorSpan redSpan = new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_FFA9A9A9));
stringBuilder.setSpan(redSpan, surplusTxt.length(), surplusTxt.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//修改最后两个字体的颜色
helper.setText(R.id.tv_gift_price,stringBuilder);
//加载礼物图片
ImageUtils.loadImageView(giftModel.getBase_image(),helper.getView(R.id.iv_gift_pic));
//设置选中后的样式
if (giftModel.isChecked()) {//被选中
helper.getView(R.id.cl_iv_down_on).setBackgroundResource(R.mipmap.room_gift_bjx);
helper.setVisible(R.id.iv_down_on, false);
} else {
helper.setVisible(R.id.iv_down_on, false);
helper.getView(R.id.cl_iv_down_on).setBackgroundResource(0);
}
}
@Override
@@ -107,68 +142,68 @@ public class GiftPackAdapter extends BaseAdapter {
@Override
@SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
public View getView(int position, View convertView, ViewGroup parent) {
GiftPackAdapter.ViewHolder viewHolder;
GiftPackBean giftModel = getItem(position);
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_gift_room, parent, false);
viewHolder = new GiftPackAdapter.ViewHolder();
viewHolder.tv_gift_name = (TextView) convertView.findViewById(R.id.tv_gift_name);
viewHolder.tv_gift_price = (TextView) convertView.findViewById(R.id.tv_gift_price);
viewHolder.iv_gift_pic = (ImageView) convertView.findViewById(R.id.iv_gift_pic);
viewHolder.item_layout = (ConstraintLayout) convertView.findViewById(R.id.cl_gift);
viewHolder.ivDownOn = (ImageView) convertView.findViewById(R.id.iv_down_on);
viewHolder.cl_iv_down_on = (ConstraintLayout) convertView.findViewById(R.id.cl_iv_down_on);
viewHolder.integral = (TextView) convertView.findViewById(R.id.integral);
viewHolder.im_heart = (ImageView) convertView.findViewById(R.id.im_heartssss);
convertView.setTag(viewHolder);
} else {
viewHolder = (GiftPackAdapter.ViewHolder) convertView.getTag();
}
viewHolder.item_layout.setOnClickListener(v -> {
// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
EventBus.getDefault().post(new RoomGiftPackToEvent(this, giftModel, 2));
});
viewHolder.integral.setVisibility(View.VISIBLE);
viewHolder.integral.setText("x"+giftModel.getNum());
//设置礼物名字
viewHolder.tv_gift_name.setText(giftModel.getGift_name());
//设置礼物价格
String surplusTxt = giftModel.getGift_price();
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(surplusTxt);
//ForegroundColorSpan 为文字前景色BackgroundColorSpan为文字背景色
ForegroundColorSpan redSpan = new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_FFA9A9A9));
stringBuilder.setSpan(redSpan, surplusTxt.length(), surplusTxt.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//修改最后两个字体的颜色
viewHolder.tv_gift_price.setText(stringBuilder);
// viewHolder.item_layout.setTag(R.id.id_gift_tag, giftModel);
//加载礼物图片
ImageUtils.loadImageView(giftModel.getBase_image(), viewHolder.iv_gift_pic);
//设置选中后的样式
if (giftModel.isChecked()) {//被选中
viewHolder.cl_iv_down_on.setBackgroundResource(R.mipmap.room_gift_bjx);
viewHolder.ivDownOn.setVisibility(View.GONE);
} else {
viewHolder.ivDownOn.setVisibility(View.GONE);
viewHolder.cl_iv_down_on.setBackgroundResource(0);
}
return convertView;
}
static class ViewHolder {
public ConstraintLayout item_layout;
public TextView tv_gift_name, tv_gift_price, integral;
public ImageView iv_gift_pic;
public TextView tv_gift_change_love_values;
public ImageView ivDownOn;
public ConstraintLayout cl_iv_down_on;
public ImageView im_heart;
}
// @Override
// @SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
// public View getView(int position, View convertView, ViewGroup parent) {
// GiftPackAdapter.ViewHolder viewHolder;
// GiftPackBean giftModel = getItem(position);
// if (convertView == null) {
// convertView = inflater.inflate(R.layout.item_gift_room, parent, false);
// viewHolder = new GiftPackAdapter.ViewHolder();
// viewHolder.tv_gift_name = (TextView) convertView.findViewById(R.id.tv_gift_name);
// viewHolder.tv_gift_price = (TextView) convertView.findViewById(R.id.tv_gift_price);
// viewHolder.iv_gift_pic = (ImageView) convertView.findViewById(R.id.iv_gift_pic);
// viewHolder.item_layout = (ConstraintLayout) convertView.findViewById(R.id.cl_gift);
// viewHolder.ivDownOn = (ImageView) convertView.findViewById(R.id.iv_down_on);
// viewHolder.cl_iv_down_on = (ConstraintLayout) convertView.findViewById(R.id.cl_iv_down_on);
// viewHolder.integral = (TextView) convertView.findViewById(R.id.integral);
// viewHolder.im_heart = (ImageView) convertView.findViewById(R.id.im_heartssss);
// convertView.setTag(viewHolder);
// } else {
// viewHolder = (GiftPackAdapter.ViewHolder) convertView.getTag();
// }
//
// viewHolder.item_layout.setOnClickListener(v -> {
//// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
// EventBus.getDefault().post(new RoomGiftPackToEvent(this, giftModel, 2));
//
// });
// viewHolder.integral.setVisibility(View.VISIBLE);
// viewHolder.integral.setText("x"+giftModel.getNum());
// //设置礼物名字
// viewHolder.tv_gift_name.setText(giftModel.getGift_name());
// //设置礼物价格
// String surplusTxt = giftModel.getGift_price();
// SpannableStringBuilder stringBuilder = new SpannableStringBuilder(surplusTxt);
// //ForegroundColorSpan 为文字前景色BackgroundColorSpan为文字背景色
// ForegroundColorSpan redSpan = new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_FFA9A9A9));
// stringBuilder.setSpan(redSpan, surplusTxt.length(), surplusTxt.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//修改最后两个字体的颜色
// viewHolder.tv_gift_price.setText(stringBuilder);
//// viewHolder.item_layout.setTag(R.id.id_gift_tag, giftModel);
//
// //加载礼物图片
// ImageUtils.loadImageView(giftModel.getBase_image(), viewHolder.iv_gift_pic);
// //设置选中后的样式
//
// if (giftModel.isChecked()) {//被选中
// viewHolder.cl_iv_down_on.setBackgroundResource(R.mipmap.room_gift_bjx);
// viewHolder.ivDownOn.setVisibility(View.GONE);
// } else {
// viewHolder.ivDownOn.setVisibility(View.GONE);
// viewHolder.cl_iv_down_on.setBackgroundResource(0);
// }
//
// return convertView;
// }
//
//
// static class ViewHolder {
// public ConstraintLayout item_layout;
// public TextView tv_gift_name, tv_gift_price, integral;
// public ImageView iv_gift_pic;
// public TextView tv_gift_change_love_values;
// public ImageView ivDownOn;
// public ConstraintLayout cl_iv_down_on;
// public ImageView im_heart;
// }
}

View File

@@ -7,6 +7,7 @@ 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;
@@ -17,8 +18,12 @@ import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.blankj.utilcode.util.LogUtils;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.hjq.toast.ToastUtils;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.bean.RoonGiftModel;
@@ -30,7 +35,7 @@ import org.greenrobot.eventbus.EventBus;
import java.lang.ref.WeakReference;
import java.util.List;
public class GiftRoomAdapter extends BaseAdapter {
public class GiftRoomAdapter extends BaseQuickAdapter<RoonGiftModel, BaseViewHolder> {
private final List<RoonGiftModel> mDatas;
private final LayoutInflater inflater;
private final Context mContext;
@@ -46,7 +51,7 @@ public class GiftRoomAdapter extends BaseAdapter {
private final int pageSize = 100;
public GiftRoomAdapter(Context context, List<RoonGiftModel> mDatas, int curIndex, String type) {
super(R.layout.item_gift_room);
this.mDatas = mDatas;
this.curIndex = curIndex;
this.mContext = context;
@@ -60,19 +65,93 @@ public class GiftRoomAdapter extends BaseAdapter {
* 如果够则直接返回每一页显示的最大条目个数pageSize,
* 如果不够,则有几项返回几,(mDatas.size() - curIndex * pageSize);(也就是最后一页的时候就显示剩余item)
*/
@Override
public int getCount() {
return mDatas.size() > (curIndex + 1) * pageSize ? pageSize : (mDatas.size() - curIndex * pageSize);
}
// @Override
// public int getCount() {
// return mDatas !=null ? mDatas.size() : 0;
//// return mDatas.size() > (curIndex + 1) * pageSize ? pageSize : (mDatas.size() - curIndex * pageSize);
// }
//
// @Override
// public RoonGiftModel getItem(int position) {
// return mDatas.get(position);
//// return mDatas.get(position + curIndex * pageSize);
// }
@Override
public RoonGiftModel getItem(int position) {
return mDatas.get(position + curIndex * pageSize);
protected void convert(@NonNull BaseViewHolder helper, RoonGiftModel giftModel) {
helper.getView(R.id.cl_gift).setOnClickListener(v -> {
// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
if (giftModel.getIs_lock() == 0) {
EventBus.getDefault().post(new RoomGiftClickToEvent(this, giftModel, 1));
} else if (giftModel.getIs_lock() == 1) {
ToastUtils.show("当前属于爵位礼物,请开通爵位");
}
});
if (giftModel.getIs_lock() == 0) {
helper.setVisible(R.id.iv_gift_select,false);
} else {
helper.setVisible(R.id.iv_gift_select,true);
}
if (TextUtils.isEmpty(giftModel.getIcon())) {
helper.setVisible(R.id.im_heartssss,false);
}else {
helper.setVisible(R.id.im_heartssss,true);
ImageUtils.loadHead(giftModel.getIcon(), helper.getView(R.id.im_heartssss));
}
//设置礼物名字
helper.setText(R.id.tv_gift_name,giftModel.getGift_name());
if (TextUtils.isEmpty(giftModel.getNum())){
helper.setVisible(R.id.integral, false);
}else {
helper.setVisible(R.id.integral, true).setText(R.id.integral, "x" + giftModel.getNum());
}
//设置礼物价格
String surplusTxt = giftModel.getGift_price();
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(surplusTxt);
//ForegroundColorSpan 为文字前景色BackgroundColorSpan为文字背景色
ForegroundColorSpan redSpan = new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_FFA9A9A9));
stringBuilder.setSpan(redSpan, surplusTxt.length(), surplusTxt.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//修改最后两个字体的颜色
helper.setText(R.id.tv_gift_price,stringBuilder);
// viewHolder.item_layout.setTag(R.id.id_gift_tag, giftModel);
//加载礼物图片
ImageUtils.loadImageView(giftModel.getBase_image(), helper.getView(R.id.iv_gift_pic));
//设置选中后的样式
if (giftModel.getGift_bag() == 10) {
helper.setText(R.id.tv_gift_name,"");
helper.getView(R.id.cl_gift).setBackgroundResource(R.mipmap.gift_tkzj);
helper.getView(R.id.tv_gift_name).setBackgroundResource(R.mipmap.gift_name_tkzj);
} else if (giftModel.getGift_bag() == 11) {
helper.setText(R.id.tv_gift_name,"");
helper.getView(R.id.cl_gift).setBackgroundResource(R.mipmap.gift_syzc);
helper.getView(R.id.tv_gift_name).setBackgroundResource(R.mipmap.gift_name_syzc);
} else if (giftModel.getGift_bag() == 12) {
helper.setText(R.id.tv_gift_name,"");
helper.getView(R.id.cl_gift).setBackgroundResource(R.mipmap.gift_sjzd);
helper.getView(R.id.tv_gift_name).setBackgroundResource(R.mipmap.gift_name_skzd);
}else {
helper.setText(R.id.tv_gift_name,giftModel.getGift_name());
helper.getView(R.id.tv_gift_name).setBackgroundResource(0);
helper.getView(R.id.cl_gift).setBackgroundResource(R.mipmap.gift_bj);
}
if (giftModel.isChecked()) {//被选中
helper.getView(R.id.cl_iv_down_on).setBackgroundResource(R.mipmap.room_gift_bjx);
helper.setVisible(R.id.iv_down_on,false);
} else {
helper.getView(R.id.cl_iv_down_on).setBackgroundResource(0);
helper.setVisible(R.id.iv_down_on,false);
}
}
@Override
public long getItemId(int position) {
return position + (long) curIndex * pageSize;
return position;
// return position + (long) curIndex * pageSize;
}
private static class MyGestureDetector extends GestureDetector {
@@ -116,124 +195,130 @@ public class GiftRoomAdapter extends BaseAdapter {
}
@Override
@SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
RoonGiftModel giftModel = getItem(position);
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_gift_room, parent, false);
viewHolder = new ViewHolder();
viewHolder.item_layout = (ConstraintLayout) convertView.findViewById(R.id.cl_gift);
viewHolder.cl_iv_down_on = (ConstraintLayout) convertView.findViewById(R.id.cl_iv_down_on);
viewHolder.tv_gift_name = (TextView) convertView.findViewById(R.id.tv_gift_name);
viewHolder.tv_gift_price = (TextView) convertView.findViewById(R.id.tv_gift_price);
viewHolder.iv_gift_pic = (ImageView) convertView.findViewById(R.id.iv_gift_pic);
viewHolder.ivDownOn = (ImageView) convertView.findViewById(R.id.iv_down_on);
viewHolder.iv_gift_select = (ImageView) convertView.findViewById(R.id.iv_gift_select);
// im_heart现在位于顶层布局中
viewHolder.im_heart = (ImageView) convertView.findViewById(R.id.im_heartssss);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.item_layout.setOnClickListener(v -> {
// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
if (giftModel.getIs_lock() == 0) {
EventBus.getDefault().post(new RoomGiftClickToEvent(this, giftModel, 1));
} else if (giftModel.getIs_lock() == 1) {
ToastUtils.show("当前属于爵位礼物,请开通爵位");
}
});
if (giftModel.getIs_lock() == 0) {
viewHolder.iv_gift_select.setVisibility(GONE);
} else {
viewHolder.iv_gift_select.setVisibility(VISIBLE);
}
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绑定显示的数据时计算正确的position = position + curIndex * pageSize
*/
// viewHolder.tv_gift_num.setVisibility(type.equals("1") ? View.VISIBLE : View.INVISIBLE);
// viewHolder.tv_gift_change_love_values.setVisibility(View.GONE);
//设置礼物名字
viewHolder.tv_gift_name.setText(giftModel.getGift_name());
//设置礼物价格
String surplusTxt = giftModel.getGift_price();
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(surplusTxt);
//ForegroundColorSpan 为文字前景色BackgroundColorSpan为文字背景色
ForegroundColorSpan redSpan = new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_FFA9A9A9));
stringBuilder.setSpan(redSpan, surplusTxt.length(), surplusTxt.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//修改最后两个字体的颜色
viewHolder.tv_gift_price.setText(stringBuilder);
// viewHolder.item_layout.setTag(R.id.id_gift_tag, giftModel);
//加载礼物图片
ImageUtils.loadImageView(giftModel.getBase_image(), viewHolder.iv_gift_pic);
//设置选中后的样式
if (giftModel.isChecked()) {//被选中
viewHolder.cl_iv_down_on.setBackgroundResource(R.mipmap.room_gift_bjx);
viewHolder.ivDownOn.setVisibility(View.GONE);
} else {
viewHolder.ivDownOn.setVisibility(View.GONE);
viewHolder.cl_iv_down_on.setBackgroundResource(0);
}
//设置
// //设置礼物心动值
// if (giftModel.getCardiac().equals("0")) {
// viewHolder.tv_gift_change_love_values.setBackgroundResource(R.mipmap.room_gift_xin_dong_reduce);
// viewHolder.tv_gift_change_love_values.setText(String.format("%s", giftModel.getCardiac()));
// @Override
// @SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
// public View getView(int position, View convertView, ViewGroup parent) {
// ViewHolder viewHolder;
// RoonGiftModel giftModel = getItem(position);
// if (convertView == null) {
// convertView = inflater.inflate(R.layout.item_gift_room, parent, false);
// viewHolder = new ViewHolder();
// viewHolder.item_layout = (ConstraintLayout) convertView.findViewById(R.id.cl_gift);
// viewHolder.cl_iv_down_on = (ConstraintLayout) convertView.findViewById(R.id.cl_iv_down_on);
// viewHolder.tv_gift_name = (TextView) convertView.findViewById(R.id.tv_gift_name);
// viewHolder.tv_gift_price = (TextView) convertView.findViewById(R.id.tv_gift_price);
// viewHolder.iv_gift_pic = (ImageView) convertView.findViewById(R.id.iv_gift_pic);
// viewHolder.ivDownOn = (ImageView) convertView.findViewById(R.id.iv_down_on);
// viewHolder.iv_gift_select = (ImageView) convertView.findViewById(R.id.iv_gift_select);
//
// // im_heart现在位于顶层布局中
// viewHolder.im_heart = (ImageView) convertView.findViewById(R.id.im_heartssss);
// convertView.setTag(viewHolder);
// } else {
// viewHolder.tv_gift_change_love_values.setBackgroundResource(R.mipmap.room_gift_xin_dong_add);
// viewHolder.tv_gift_change_love_values.setText(String.format("+%s", giftModel.getCardiac()));
// viewHolder = (ViewHolder) convertView.getTag();
// }
// if (giftModel.isManghe()) {
// viewHolder.tv_gift_change_love_values.setVisibility(View.GONE);
//
// viewHolder.item_layout.setOnClickListener(v -> {
//// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
// if (giftModel.getIs_lock() == 0) {
// EventBus.getDefault().post(new RoomGiftClickToEvent(this, giftModel, 1));
// } else if (giftModel.getIs_lock() == 1) {
// ToastUtils.show("当前属于爵位礼物,请开通爵位");
// }
// });
// if (giftModel.getIs_lock() == 0) {
// viewHolder.iv_gift_select.setVisibility(GONE);
// } else {
// viewHolder.iv_gift_select.setVisibility(VISIBLE);
// }
if (giftModel.getGift_bag() == 10) {
viewHolder.item_layout.setBackgroundResource(R.mipmap.gift_tkzj);
viewHolder.tv_gift_name.setText("");
viewHolder.tv_gift_name.setBackgroundResource(R.mipmap.gift_name_tkzj);
} else if (giftModel.getGift_bag() == 11) {
viewHolder.tv_gift_name.setText("");
viewHolder.item_layout.setBackgroundResource(R.mipmap.gift_syzc);
viewHolder.tv_gift_name.setBackgroundResource(R.mipmap.gift_name_syzc);
} else if (giftModel.getGift_bag() == 12) {
viewHolder.tv_gift_name.setText("");
viewHolder.item_layout.setBackgroundResource(R.mipmap.gift_sjzd);
viewHolder.tv_gift_name.setBackgroundResource(R.mipmap.gift_name_skzd);
}
return convertView;
}
static class ViewHolder {
public ConstraintLayout item_layout;
public TextView tv_gift_name, tv_gift_price, tv_gift_num;
public ImageView iv_gift_pic;
public TextView tv_gift_change_love_values;
public ImageView ivDownOn;
public ImageView iv_gift_select;
public ImageView im_heart;
public ConstraintLayout cl_iv_down_on;
}
// 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);
//// }
//// }
//// }
//
//
// /*
// * 在给View绑定显示的数据时计算正确的position = position + curIndex * pageSize
// */
//// viewHolder.tv_gift_num.setVisibility(type.equals("1") ? View.VISIBLE : View.INVISIBLE);
//// viewHolder.tv_gift_change_love_values.setVisibility(View.GONE);
//
//
// //设置礼物名字
// viewHolder.tv_gift_name.setText(giftModel.getGift_name());
// //设置礼物价格
// String surplusTxt = giftModel.getGift_price();
// SpannableStringBuilder stringBuilder = new SpannableStringBuilder(surplusTxt);
// //ForegroundColorSpan 为文字前景色BackgroundColorSpan为文字背景色
// ForegroundColorSpan redSpan = new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_FFA9A9A9));
// stringBuilder.setSpan(redSpan, surplusTxt.length(), surplusTxt.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//修改最后两个字体的颜色
// viewHolder.tv_gift_price.setText(stringBuilder);
//// viewHolder.item_layout.setTag(R.id.id_gift_tag, giftModel);
//
// //加载礼物图片
// ImageUtils.loadImageView(giftModel.getBase_image(), viewHolder.iv_gift_pic);
// //设置选中后的样式
//
// if (giftModel.isChecked()) {//被选中
// viewHolder.cl_iv_down_on.setBackgroundResource(R.mipmap.room_gift_bjx);
// viewHolder.ivDownOn.setVisibility(View.GONE);
// } else {
// viewHolder.ivDownOn.setVisibility(View.GONE);
// viewHolder.cl_iv_down_on.setBackgroundResource(0);
// }
// //设置
//// //设置礼物心动值
//// if (giftModel.getCardiac().equals("0")) {
//// viewHolder.tv_gift_change_love_values.setBackgroundResource(R.mipmap.room_gift_xin_dong_reduce);
//// viewHolder.tv_gift_change_love_values.setText(String.format("%s", giftModel.getCardiac()));
//// } else {
//// viewHolder.tv_gift_change_love_values.setBackgroundResource(R.mipmap.room_gift_xin_dong_add);
//// viewHolder.tv_gift_change_love_values.setText(String.format("+%s", giftModel.getCardiac()));
//// }
//// if (giftModel.isManghe()) {
//// viewHolder.tv_gift_change_love_values.setVisibility(View.GONE);
//// }
// if (giftModel.getGift_bag() == 10) {
//
// viewHolder.item_layout.setBackgroundResource(R.mipmap.gift_tkzj);
// viewHolder.tv_gift_name.setText("");
// viewHolder.tv_gift_name.setBackgroundResource(R.mipmap.gift_name_tkzj);
// } else if (giftModel.getGift_bag() == 11) {
// viewHolder.tv_gift_name.setText("");
// viewHolder.item_layout.setBackgroundResource(R.mipmap.gift_syzc);
// viewHolder.tv_gift_name.setBackgroundResource(R.mipmap.gift_name_syzc);
// } else if (giftModel.getGift_bag() == 12) {
// viewHolder.tv_gift_name.setText("");
// viewHolder.item_layout.setBackgroundResource(R.mipmap.gift_sjzd);
// viewHolder.tv_gift_name.setBackgroundResource(R.mipmap.gift_name_skzd);
// }
// return convertView;
// }
//
//
// static class ViewHolder {
// public ConstraintLayout item_layout;
// public TextView tv_gift_name, tv_gift_price, tv_gift_num;
// public ImageView iv_gift_pic;
// public TextView tv_gift_change_love_values;
// public ImageView ivDownOn;
// public ImageView iv_gift_select;
// public ImageView im_heart;
// public ConstraintLayout cl_iv_down_on;
// }
}

View File

@@ -79,7 +79,7 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
}
public void loadDataIfNeeded(String id, int type, String roomId) {
if (MvpPre==null){
if (MvpPre == null) {
MvpPre = new RewardGiftPresenter(this, getActivity());
}
if (id.equals("0")) {
@@ -95,11 +95,12 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
}
}
bdgiftId = "";
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onString(GiftPackEvent event) {
if (event!=null && event.getBdid()!=null) {
if (event != null && event.getBdid() != null) {
bdgiftId = event.getBdid();
MvpPre.giftPack();
}
@@ -107,7 +108,7 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
@Override
protected void initData() {
if (type==0){
if (type == 0) {//当type=0的时候这个是点击排麦插队礼物的这里传递的id是0
MvpPre.getGiftList("0", type, roomId);
}
}
@@ -157,6 +158,7 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
if (pageCount > 0) {
roomAdapter = new GiftRoomAdapter(CommonAppContext.getInstance(), data, 0, "0");
mBinding.rvGift.setAdapter(roomAdapter);
roomAdapter.setNewData(data);
}
}
@@ -223,6 +225,11 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
}
@Override
public void roomHotCard() {
}
@Override
public void getRewardList(List<RewardUserBean> rewardUserBeanList) {
@@ -300,7 +307,7 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
giftModel.setChecked(true);
roonGiftModel.setChecked(giftModel.isChecked());
EventBus.getDefault().post(new GiftUserRefreshEvent(true, event.type, roonGiftModel));
}else {
} else {
giftModel.setChecked(false);
roonGiftModel.setChecked(giftModel.isChecked());
}
@@ -330,7 +337,7 @@ public class GiftTwoDetailsFragment extends BaseMvpFragment<RewardGiftPresenter,
giftModel.setChecked(true);
roonGiftModel.setChecked(giftModel.isChecked());
EventBus.getDefault().post(new GiftUserRefreshEvent(true, event.type, roonGiftModel));
}else {
} else {
giftModel.setChecked(false);
roonGiftModel.setChecked(giftModel.isChecked());
EventBus.getDefault().post(new GiftUserRefreshEvent(true, event.type, roonGiftModel));

View File

@@ -0,0 +1,74 @@
package com.xscm.moduleutil.base
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import androidx.viewbinding.ViewBinding
import com.voice.lib_base.ext.inflateBindingWithGeneric
import com.xscm.moduleutil.R
open class BaseBottomFragmentDialog<B : ViewBinding?>(private val resourceID: Int) :
DialogFragment() {
var mDatabind: B? = null
val mBinding: B get() = mDatabind!!
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = Dialog(requireActivity(), R.style.myChooseDialog)
mDatabind = DataBindingUtil.inflate(LayoutInflater.from(requireContext()), resourceID, null, false) as B
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(mBinding!!.root)
val window = dialog.window
val params = window!!.attributes
params.width = WindowManager.LayoutParams.MATCH_PARENT
params.height = WindowManager.LayoutParams.WRAP_CONTENT
params.gravity = Gravity.BOTTOM
window.attributes = params
dialog.setCanceledOnTouchOutside(true)
return dialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mDatabind = inflateBindingWithGeneric(inflater, container, false)
// return if (mBinding != null) mBinding!!.root else mDatabind?.root
return mBinding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(requireDialog().window!!, false)
requireDialog().setOnShowListener { dialog: DialogInterface? ->
(view.parent as ViewGroup).setBackgroundColor(
Color.TRANSPARENT
)
}
}
override fun onDestroyView() {
super.onDestroyView()
mDatabind = null
}
fun setBundleArgs(bundleArgs: Bundle?): BaseBottomFragmentDialog<B> {
arguments = bundleArgs
return this
}
}

View File

@@ -0,0 +1,68 @@
package com.xscm.moduleutil.base
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.DialogFragment
import androidx.viewbinding.ViewBinding
import com.voice.lib_base.ext.inflateBindingWithGeneric
import com.xscm.moduleutil.R
open class BaseFragmentDialog<B : ViewBinding?>(private val resourceID: Int) : DialogFragment() {
var mDatabind: B? = null
val mBinding: B get() = mDatabind!!
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = Dialog(requireActivity(), R.style.myChooseDialog)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
mDatabind = DataBindingUtil.inflate<ViewDataBinding>(LayoutInflater.from(requireContext()), resourceID, null, false) as B
dialog.setContentView(mDatabind!!.root)
val window = dialog.window
val params = window!!.attributes
params.width = WindowManager.LayoutParams.MATCH_PARENT
params.height = WindowManager.LayoutParams.WRAP_CONTENT
window.attributes = params
dialog.setCanceledOnTouchOutside(true)
return dialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mDatabind = inflateBindingWithGeneric(inflater, container, false)
return if (mBinding != null) mBinding!!.root else null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(requireDialog().window!!, false)
requireDialog().setOnShowListener { dialog: DialogInterface? ->
(view.parent as ViewGroup).setBackgroundColor(
Color.TRANSPARENT
)
}
}
override fun onDestroyView() {
super.onDestroyView()
mDatabind = null
}
fun setBundleArgs(bundleArgs: Bundle?): BaseFragmentDialog<B> {
arguments = bundleArgs
return this
}
}

View File

@@ -0,0 +1,65 @@
package com.xscm.moduleutil.base
import androidx.lifecycle.*
import com.xscm.moduleutil.http.RetrofitClient
import com.xscm.moduleutil.widget.room.PassRoomException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import okhttp3.MultipartBody
/**
*
*/
open class BaseViewModel : ViewModel(), LifecycleObserver {
private var clickTime: Long = 0
var baseRepository = RetrofitClient.getInstance()
private val passRoom by lazy { MutableLiveData<Exception>() }
private val error by lazy { MutableLiveData<Exception>() }
private val finally by lazy { MutableLiveData<Int>() }
//进入房间
var imgListData: MutableLiveData<List<String>> = MutableLiveData()
var addImgData = MutableLiveData<Any>()
//运行在UI线程的协程
fun launchUI(block: suspend CoroutineScope.() -> Unit) = viewModelScope.launch {
try {
block()
} catch (e: Exception) {
if (e is PassRoomException) {
passRoom.value = e
} else {
error.value = e
// throw e
}
} finally {
finally.value = 200
}
}
/**
* 请求失败,出现异常
*/
fun getError(): LiveData<Exception> {
return error
}
/**
* 请求完成,在此处做一些关闭操作
*/
fun getFinally(): LiveData<Int> {
return finally
}
}

View File

@@ -26,6 +26,7 @@ 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;
@@ -43,6 +44,7 @@ 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;
@@ -75,7 +77,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;
@@ -95,17 +97,19 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
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 isMai = false;
public boolean isLogout = false;
public void onAppBackground() {
wasInBackground = true;
@@ -123,16 +127,24 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
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 = "88";
public String appVersionName = "1.0.9.8";
@Override
public void onCreate() {
super.onCreate();
@@ -154,14 +166,18 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
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(true);
ExternalResConstants.INSTANCE.setIS_HTTP_RELEASE(selectRelease);
currentEnvironment = ExternalResConstants.INSTANCE.HTTP_PATH();
initialization();
@@ -209,6 +225,58 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
}
}
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);
}
}
public void clearLoginDialog(String msg){
new ConfirmDialog(ActivityUtils.getTopActivity(),
"提示",
msg,
"",
"确定",
v -> {
// 点击“确认”按钮时执行删除操作
},
v -> {
try {
clearLoginInfo();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
// 点击“取消”按钮时什么都不做
}, true, 4).show();
}
// 更新未读消息数的方法
private void updateUnreadMessageCount() {
V2TIMManager.getConversationManager().getTotalUnreadMessageCount(new V2TIMValueCallback<Long>() {
@@ -228,17 +296,19 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
// 通知未读数变化的方法可以发送广播或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() {
@@ -749,20 +819,25 @@ public class CommonAppContext extends MultiDexApplication implements Applicatio
SpUtil.putToken("");
// piaoPingManager.unsubscribe();
FileUtils.deleteAllInDir(getCacheDir());
FileUtils.deleteAllInDir(getExternalCacheDir());
// TODO: 2026/1/22 清楚本地缓存,但是在清楚的时候,会把所有的图片缓存就清除了,这是不对的,今天进行了修改,注释掉
// FileUtils.deleteAllInDir(getCacheDir());
// FileUtils.deleteAllInDir(getExternalCacheDir());
AgoraManager.getInstance().destroy();
// 每次启动应用时重置状态
SpUtil.setBooleanValue("youth_model_shown", false);
if (mqttConnect != null){
mqttConnect.close();
mqttConnect = null;
}
isLogout = true;
// 发送广播通知所有Activity刷新状态
Intent refreshIntent = new Intent("com.xscm.moduleutil.ACTION_USER_LOGOUT");
sendBroadcast(refreshIntent);
// Intent refreshIntent = new Intent("com.xscm.moduleutil.ACTION_USER_LOGOUT");
// sendBroadcast(refreshIntent);
ActivityUtils.finishAllActivities();
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,12 +17,15 @@ object ExternalResConstants {
// }
// }
//================================================================================HTTP======================================================================================
var IS_HTTP_RELEASE = true
val HTTP_PATH_DEBUG:EnvironmentEnum = EnvironmentEnum.TEST
val HTTP_PATH_RELEASE:EnvironmentEnum = EnvironmentEnum.PRODUCTION
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
fun HTTP_PATH(): EnvironmentEnum {
return if (IS_HTTP_RELEASE) {
return if (IS_HTTP_RELEASE == 1) {
HTTP_PATH_RELEASE
} else if (IS_HTTP_RELEASE == 3) {
HTTP_AUXILIARY
} else {
HTTP_PATH_DEBUG
}

View File

@@ -0,0 +1,10 @@
package com.xscm.moduleutil.base;
public class RealTimeMessages<T> {
public T data;
public int code;
}

View File

@@ -0,0 +1,6 @@
package com.xscm.moduleutil.base
data class SocketBean(
val code: Int, val data: Any
)

View File

@@ -0,0 +1,11 @@
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

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

View File

@@ -0,0 +1,28 @@
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;
private int is_follow;// 是否关注 0:未关注 1已关注 2别人关注了你你没有关注别人这个2只会在粉丝中使用
private List<String> icon;
}

View File

@@ -0,0 +1,20 @@
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

@@ -0,0 +1,174 @@
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

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

View File

@@ -41,7 +41,8 @@ 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(senderName, other.senderName) &&
Objects.equals(nickname,other.nickname);
}
// 生成礼物唯一键

View File

@@ -61,7 +61,8 @@ 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

@@ -0,0 +1,22 @@
package com.xscm.moduleutil.bean
import java.util.ArrayList
/**
* 项目名称:羽声语音
* 时间2026/1/23 9:59
* 用途:礼物墙用户列表
*/
class GiftWallUserBean {
var count : Int = 0
var users :List<GiftWallUserItemBean> = ArrayList()
class GiftWallUserItemBean {
var avatar : String = ""
var nickname : String = ""
var user_id : String = ""
var count : Int = 0
}
}

View File

@@ -0,0 +1,54 @@
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是 ,其他的不是 2:管理员 3普通成员
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不是
var group_role : Int = 0 //群角色 1群主 2管理员 3普通成员
}
/*"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

@@ -0,0 +1,13 @@
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,6 +20,7 @@ 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,6 +54,7 @@ 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

@@ -0,0 +1,57 @@
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

@@ -0,0 +1,13 @@
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

@@ -0,0 +1,11 @@
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 String id;
private int 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;//麦位
private String pit_number;//麦位 酒吧房的情况下这个是抱麦的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下麦
private int type;//拍卖者1上麦、2下麦 暴币的时候1是大奖 2是小奖 在酒吧房的时候, 0没有选择自定义礼物 1选择了自定义礼物
private String hot_value;
private String SendRoomId;//发起者所在的房间ID
private String AcceptRoomId;//接收者所在的房间id
private String PkId;
private String room_id;//当type==1的时候。这个roomId是对方的房间id
private String user_id = "";
private String room_id;//当type==1的时候。这个roomId是对方的房间id 当是酒吧房的时候就是需要进入的小房间的id
private String user_id = ""; //当是酒吧房的时候,这个值就是要进入小黑屋的房主信息
private String pk_end_times;//pk结束时间
private List<RoomPitBean> userCharmList;
@@ -114,6 +114,10 @@ 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

@@ -26,6 +26,8 @@ public class RoomSearchResp {
private int label_id;
private String today_hot_value;
private String room_password;

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,9 +34,18 @@ 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

@@ -0,0 +1,11 @@
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,5 +1,8 @@
package com.xscm.moduleutil.bean;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.base.CommonAppContext;
import lombok.Data;
/**
@@ -9,17 +12,115 @@ import lombok.Data;
*/
@Data
public class ThemeBean {
private String theme_color;//主题颜色
private int is_open;
private String theme_name;
private String theme_color="#22BB79";//主题颜色
private String file_url;//
private String auxiliary_color;//
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;//我的未选中
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;
}
}

View File

@@ -98,6 +98,8 @@ 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;//金币
private String coin="0";//金币
private String earnings;//钻石
private String url;//灵活就业合作伙伴协议
private String title;//状态

View File

@@ -18,6 +18,10 @@ public class BlindReslutBean {
public class ReslutList {
private int gift_id;//中奖礼物Id
private int count;//中奖礼物数量
private String gift_price = "";
private String gift_name = "";
private String base_image = "";
}
}

View File

@@ -11,10 +11,21 @@ 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;
/// 设置管理员
@@ -48,12 +59,11 @@ 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;
/// 主持延时
@@ -101,8 +111,7 @@ 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;
/// 小黑屋有人退出房间
@@ -129,8 +138,7 @@ 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;
@@ -150,6 +158,20 @@ 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;
@@ -204,9 +226,11 @@ 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

@@ -19,4 +19,6 @@ public class PkRoomInfo implements Serializable {
private String pk_part;;//2等待开始、3进行中、4惩罚阶段
private String pk_end_times;
private int receive_pk_user_id = -2;//接受pk的用户id
private String close_users="";//关闭pk麦克风的用户id
}

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:签约
private String type_id;//房间类型 1:点唱(pk) 2拍卖真爱拍小黑屋 3/4交友 6小黑屋 7:互娱 8交友 10:签约 11:酒吧房
private String type_name;//房间类型名称
private String user_id;//房主id
private String label_id;//类型id 2:ktv type:1/3/4/8
@@ -89,6 +89,7 @@ public class RoomBean implements Serializable {
private int queue_number;//排麦队列人数
private HeadlineBean head_line;
private int sexy_coin;//酒吧房撩的金币
private String room_code;
private String popularity;
@@ -128,6 +129,11 @@ public class RoomBean implements Serializable {
private int is_pk; //1接收 2不接受
private int last_pk_room_id;//记录上次pk的房间id
private String start_time="";//营业时间的开始时间
private String end_time="";//营业时间的结束时间
private String room_password = "";//房间密码
public int getSceneId() {
if (sound_effect != null) {
return sound_effect.getId();

View File

@@ -28,6 +28,8 @@ public class RoomHourBean extends BaseEvent {
private String label_icon;
private int xlh_status;
private int redpacket_status;// >0 有红包,=0 没有红包
private String room_password;
}
}

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;
private MusicSongBean song_user_info;//ktv
private MusicSongBean nextInfo;
private RoomAuction room_auction;//拍卖房信息
private RoomCpUserBean cp_user;

View File

@@ -50,7 +50,6 @@ public class RoomPitBean implements Serializable ,Cloneable{
private String dress;//麦位用户头像装扮
private String charm;//麦位上用户在当前房间的魅力值
private String room_id;
private String voice;
private String shutup;
@@ -77,9 +76,10 @@ 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,6 +2,8 @@ package com.xscm.moduleutil.bean.room;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import java.util.List;
import lombok.Data;
@Data
@@ -24,6 +26,8 @@ public class RoomSettingBean implements MultiItemEntity {
public static final int QXRoomSettingTypeRoomTypeLianG = 31;
//签约
public static final int QXRoomSettingTypeRoomTypeSIGNCONTRACT = 32;
//酒吧房
public static final int QXRoomSettingTypeRoomTypePUBROOM = 36;
/// 常用工具
/// 房间补贴
@@ -57,6 +61,16 @@ 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 QXRoomSettingTypeRoomBusinessTime = 37;//营业时间
public static final int QXRoomSettingTypeRoomBusinessLegend = 38;//炼仙传说
public static final int QXRoomSettingTypeRoomBusinessLOVE = 39;//爱豆计划
public static final int ITEM_TYPE_DEFAULT = 0;
public static final int ITEM_TYPE_WITH_ICON = 1;
@@ -70,7 +84,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;
@@ -96,6 +110,7 @@ public class RoomSettingBean implements MultiItemEntity {
this.itemType = ITEM_TYPE_WITH_ICON;
}
}
// public void updateItemType() {
// switch (type) {
// case QXRoomSettingTypeRoomSubsidy:

View File

@@ -0,0 +1,111 @@
package com.xscm.moduleutil.bean.room.refining
data class BoxJiangChiBean(
var gid: String = "",
var gift_name: String = "",
var gift_price: String = "",
var base_image: String = "",
var play_image: String = ""
)
data class MonsterLogBean(
val add_time: Int,
val id: Int,
val is_evil_wind: Int,
val is_join: Int,
val win_type: Int,
val win_type_data: List<WinTypeData>,
val join_data: List<WinTypeData>,
val base_image: String,
val gift_name: String,
val gift_price: Int,
val num: Int,
val type_name: String,
)
data class WinTypeData(
val type: Int, val type_name: String,
val num: Int
)
data class MonsterUserLogBean(
val add_time: Int,
val base64_nick_name: String,
val base_image: String,
val gift_name: String,
val gift_price: String,
val head_pic: String,
val id: Int,
val mid: Int,
val nick_name: String,
val num: Int,
val type_name: String,
val uid: Int,
val win_type: Int
)
data class MonsterInfoBean(
val integral: String,
val is_finsh: Int,
val multiple_list: List<Multiple>,
val open_monster_price: String,
val surplus_time: Int,
val win_number: Int
)
data class Multiple(
val id: Int,
val multiple: Double,
val type_name: String,
val num: Int,
val type: Int
)
data class MonsterResultBean(
val head_pic: String,
val id: String,
val integral: String,
val nick_name: String,
val num: Int,
val price: Int,
val type: String,
val type_name: String,
val uid: Int
)
data class MonsterEndBean(
val game_name: String,
val gift_name: String,
val is_finsh: Int,
val is_push_message: Int,
val multiple_list: List<Multiple>,
val num: Int,
val surplus_time: Int,
val total_gift_price: Int,
val win_count: Int,
val win_number: Int,
val win_type_name: String,
val base_image: String
)
data class OpenMonsterBean(
val base_image: String, // 礼物图片
val gid: Int, // 礼物id
val gift_name: String, // 礼物名称
val gift_price: String, // 礼物价格
val is_win: Int,// 是否中奖 2未中奖 1中奖
val num: Int, // 中奖数量
val total_gift_price: Int, // 总价格
val type_name: String, // 中奖类型
val win_type: Int // 中奖类型
)

View File

@@ -22,6 +22,7 @@ public class ZhuangBanShangChengBean {
private boolean is_select = false;
private int num ;//数量
private String ext_value="" ;//这是使用降身卡的时候返回的参数对应的是降身卡的前面类似10%
private String price ="";//价格
public boolean isIs_select() {
return is_select;

View File

@@ -80,6 +80,7 @@ public class ConfirmDialog extends Dialog {
window.setGravity(Gravity.CENTER); // 居中显示
window.setBackgroundDrawableResource(R.drawable.bg_r16_fff); // 透明背景
}
setCanceledOnTouchOutside(false); // 设置点击外部不取消对话框
}
@Override
protected void onCreate(Bundle savedInstanceState) {

View File

@@ -15,7 +15,9 @@ 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;
@@ -29,6 +31,7 @@ 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;
@@ -105,7 +108,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;
@@ -116,16 +119,24 @@ 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);
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();
}
}
@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){
if (nickNameTextView != null && item.getNickname() != null) {
nickNameTextView.setText(item.getNickname());
String nickName = "赠予";
String fullText = nickName + " " + item.getNickname();

View File

@@ -115,6 +115,9 @@ public class GiftLotteryDialogFragment extends BaseMvpDialogFragment<GiftLottery
}else if (giftBagId.equals("12")){
mBinding.clRoot.setBackgroundResource(R.mipmap.skzj);
mBinding.imJc.setImageResource(R.mipmap.skzl_jl);
}else if (giftBagId.equals("61")){
mBinding.clRoot.setBackgroundResource(R.mipmap.icon_love_record_bg);
mBinding.imJc.setImageResource(R.mipmap.skzl_jl);
}
mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() {

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

@@ -81,6 +81,9 @@ public class PrizePoolDialog extends BaseDialog<DialogPrizePoolBinding> {
}else if (type == 13){
mBinding.clPrize.setBackgroundResource(R.mipmap.xlh);
mBinding.imJc.setImageResource(R.mipmap.xlh_jc);
}else if (type == 38){
mBinding.clPrize.setBackgroundResource(R.mipmap.icon_love_record_bg);
mBinding.imJc.setImageResource(R.mipmap.xlh_jc);
}
// 根据屏幕密度调整行数和列数

View File

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

View File

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

View File

@@ -15,6 +15,8 @@ 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

@@ -6,6 +6,11 @@ import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean;
import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean;
import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean;
import com.xscm.moduleutil.bean.room.*;
import com.xscm.moduleutil.bean.room.refining.BoxJiangChiBean;
import com.xscm.moduleutil.bean.room.refining.MonsterInfoBean;
import com.xscm.moduleutil.bean.room.refining.MonsterLogBean;
import com.xscm.moduleutil.bean.room.refining.MonsterResultBean;
import com.xscm.moduleutil.bean.room.refining.MonsterUserLogBean;
import com.xscm.moduleutil.bean.zhuangb.ZhuangBanShangChengBean;
import com.xscm.moduleutil.utils.cos.TempKeyBean;
import com.xscm.moduleutil.widget.Constants;
@@ -26,7 +31,7 @@ public interface ApiServer {
@FormUrlEncoded //请求验证码
@POST(Constants.SEND_CODE)
Observable<BaseModel<Object>> sendCode(@Field("mobile") String mobile, @Field("event") String event);
Call<BaseModel<String>> sendCode(@Field("mobile") String mobile, @Field("event") String event);
@FormUrlEncoded
@POST(Constants.LOGIN)
@@ -38,8 +43,21 @@ 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);
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);
@FormUrlEncoded
@POST(Constants.POST_GIFT_WALL_USER_LIST) //礼物墙礼物用户列表
Call<BaseModel<GiftWallUserBean>> giftWallUserList( @Field("user_id") String user_id,@Field("gift_id")String gift_id,@Field("page") int page);
@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();
@@ -106,7 +124,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_LOG_LIST)
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);
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);
@FormUrlEncoded
@POST(Constants.POST_WEALTH_RANKING)
@@ -129,6 +147,16 @@ 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();
@@ -254,7 +282,8 @@ 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_THEME_DATA)
@GET(Constants.GET_FESTIVAL_THEME)
Call<BaseModel<ThemeBean>> getThemeData();
@FormUrlEncoded
@@ -324,19 +353,28 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.CHECK_TXT)
Call<ResponseBody> checkTxt(@Field("room_name") String room_name, @Field("room_cover") String room_cover, @Field("room_intro") String room_intro);
Call<ResponseBody> checkTxt(@Field("room_name") String room_name, @Field("room_cover") String room_cover, @Field("room_intro") String room_intro,@Field("room_password") String room_password);
@FormUrlEncoded
@POST(Constants.GET_REWARD_LIST)
Call<BaseModel<List<RewardUserBean>>> getRewardList(@Field("id") String id, @Field("page") String page, @Field("page_limit") String page_limit);
@GET(Constants.GET_GIFT_LABEL)
Call<BaseModel<List<GiftLabelBean>>> getGiftLabel(@Query("have_hot") String have_hot);
Call<BaseModel<List<GiftLabelBean>>> getGiftLabel(@Query("type") String type);
//获取礼物列表
@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) //拍卖位选择拍卖礼物type=3 label =99
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);
@@ -420,6 +458,17 @@ 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);
@@ -439,8 +488,8 @@ public interface ApiServer {
@POST(Constants.GET_ALBUM_DETAIL)
Call<BaseModel<AlbumBean>> getAlbumDetail(@Field("album_id") String albumId, @Field("pwd") String pwd, @Field("page") String page, @Field("page_limit") String page_limit);
@GET(Constants.GET_PERSONALTY)
Call<BaseModel<List<PersonaltyBean>>> getPersonaltyList();
@GET(Constants.GET_PERSONALTY) // from 来源: 1:道具商城 2个性装扮
Call<BaseModel<List<PersonaltyBean>>> getPersonaltyList(@Query("from")String frome);
@FormUrlEncoded
@POST(Constants.GET_SUBSIDY)
@@ -449,6 +498,17 @@ 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);
@@ -477,10 +537,33 @@ public interface ApiServer {
@POST(Constants.postRoomSwToken)
Call<BaseModel<PkSwTokenBean>> postRoomSwToken(@Field("room_id") String roomId);
@FormUrlEncoded
@POST(Constants.POST_CLOSE_PK_MIC)
Call<BaseModel<String>> closePkMic(@Field("pk_id") String pk_id,@Field("type") String type,@Field("user_id") String user_id);
@FormUrlEncoded
@POST(Constants.SET_USER_DECORATE)
Call<BaseModel<String>> setUserDecorate(@Field("udid") String udid);
@GET(Constants.GET_MONSTER_INFO_BOX)
Call<BaseModel<MonsterInfoBean>> get_monster_info_box();
@GET(Constants.GET_OPEN_BEAT_MONSTER)
Call<BaseModel<MonsterResultBean>> open_beat_monster(@Query("rid")String rid,@Query("type") String type,@Query("num") String num);
@GET(Constants.GET_MONSTER_BOX_LIST)
Call<BaseModel<List<BoxJiangChiBean>>> get_monster_box_list();
@GET(Constants.GET_USER_MONSTER_LOG)
Call<BaseModel<List<MonsterUserLogBean>>> get_user_monster_log(@Query("page")String page);
@GET(Constants.GET_MONSTER_LOG)
Call<BaseModel<List<MonsterLogBean>>> get_monster_log(@Query("page")String page,@Query("page_limit")String page_limit);
@GET(Constants.GET_MONSTER_NOTE)
Call<BaseModel<String>> get_monster_note();
@FormUrlEncoded
@POST(Constants.POST_CANCEL_USER_DECORATE)
Call<BaseModel<String>> cancelUserDecorate(@Field("type") String type);
@@ -496,12 +579,18 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.JOIN_ROOM)
Call<BaseModel<RoomInfoResp>> roomGetIn(@Field("room_id") String roomId, @Field("password") String password);
Call<BaseModel<RoomInfoResp>> roomGetIn(@Field("room_id") String roomId, @Field("room_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);
@@ -532,7 +621,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);
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);
@FormUrlEncoded
@POST(Constants.POST_CP_GIVE_GIFT)
@@ -556,6 +645,12 @@ 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,
@@ -609,7 +704,11 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.APPLY_PIT)
Call<BaseModel<String>> applyPit(@Field("room_id") String room_id, @Field("pit_number") String pit_number);
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);
@FormUrlEncoded
@POST(Constants.START_FRIEND)
@@ -629,7 +728,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_KEEP_XINTIAO)
Call<ResponseBody> keepXintiao(@Field("room_id") String room_id);
Call<BaseModel<TasksMessage>> keepXintiao(@Field("room_id") String room_id);
@FormUrlEncoded
@POST(Constants.DOWN_PIT)
@@ -679,6 +778,13 @@ 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.SET_ROOM_BUSINESS_TIME)
Call<BaseModel<String>> setRoomBusinessTime(@Field("room_id") String roomId,@Field("start_time") String startTime,@Field("end_time") String endTime);
@FormUrlEncoded
@POST(Constants.POST_END_SONG)
Call<BaseModel<String>> endSong(@Field("room_id") String roomId);
@@ -689,7 +795,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.CHANGE_SONG)
Call<BaseModel<String>> changeSong(@Field("room_id") String roomId, @Field("now_did") String now_did);
Call<BaseModel<String>> changeSong(@Field("room_id") String roomId, @Field("now_did") String now_did,@Field("is_auto_next") String is_auto_next);
@FormUrlEncoded
@POST(Constants.POST_HOST_LIST)
@@ -700,7 +806,7 @@ public interface ApiServer {
Call<BaseModel<List<RoomCharmRankBean>>> getCharmRank(@Field("room_id") String roomId);
@FormUrlEncoded
@POST(Constants.POST_ROOM_RELATION_LIST)
@POST(Constants.POST_ROOM_RELATION_LIST) //1真爱拍 2亲密拍 3星球互娱
Call<BaseModel<List<RoomRelationBean>>> roomRelationList(@Field("type") String type);
@FormUrlEncoded
@@ -766,7 +872,7 @@ public interface ApiServer {
@FormUrlEncoded
@POST(Constants.POST_EDIT_ROOM)
Call<BaseModel<String>> editRoom(@Field("room_id") String room_id, @Field("room_name") String room_name, @Field("room_cover") String room_cover, @Field("room_intro") String room_intro, @Field("room_background") String room_background);
Call<BaseModel<String>> editRoom(@Field("room_id") String room_id, @Field("room_name") String room_name, @Field("room_cover") String room_cover, @Field("room_intro") String room_intro, @Field("room_background") String room_background,@Field("room_password")String room_password);
@FormUrlEncoded
@POST(Constants.POST_KICK_OUT_ROOM)
@@ -803,7 +909,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);
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);
@FormUrlEncoded
@@ -868,6 +974,17 @@ public interface ApiServer {
@GET(Constants.GET_GIFT_PACK_LIST_COUNT)
Call<BaseModel<GiftPackListCount>> getGiftPackListCount();
@FormUrlEncoded
@POST(Constants.POST_ROOM_HOT_CARD)
Call<BaseModel<String>> roomHotCard(@Field("udid") String udid, @Field("room_id") String room_id, @Field("num") String num);
@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

@@ -0,0 +1,61 @@
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,7 +91,9 @@ 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

@@ -0,0 +1,5 @@
package com.xscm.moduleutil.listener
interface JoinRoomErrorListener {
fun onJoinRoomError(errorCode: Int, errorMsg: String)
}

View File

@@ -0,0 +1,703 @@
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,6 +41,8 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import lombok.Getter;
/**
* @author qx
* @data 2025/6/17
@@ -52,7 +54,8 @@ public class MessageListenerSingleton {
private List<OnMessageReceivedListener> listeners = new ArrayList<>();
private V2TIMSimpleMsgListener simpleMsgListener;
private V2TIMAdvancedMsgListener v2TIMAdvancedMsgListener;
private static String mRoomId = "";
@Getter
public String mRoomId = "";
public static String groupId;
private V2TIMGroupListener groupListener;
private V2TIMConversationListener conversationListener; // 需要保存引用
@@ -96,7 +99,6 @@ public class MessageListenerSingleton {
// 同时修改 removePublicScreenMessageListener 方法
public void removePublicScreenMessageListener(PublicScreenMessageListener listener) {
mRoomId = "";
if (listener == null) {
return;
}
@@ -205,16 +207,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), 100);
mainHandler.postDelayed(() -> joinGroup(roomId), 200);
return;
}
@@ -313,7 +315,7 @@ public class MessageListenerSingleton {
simpleMsgListener = new V2TIMSimpleMsgListener() {
@Override
public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {
LogUtils.d("C2C 文本消息 " + sender.getNickName());
LogUtils.d("C2C 文本消息 " + text);
}
@Override
@@ -321,7 +323,9 @@ public class MessageListenerSingleton {
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) {
if (event.getMsgType() == 404){
CommonAppContext.getInstance().clearLoginDialog(event.getText().getText());
}else 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()) {
@@ -340,12 +344,14 @@ public class MessageListenerSingleton {
@Override
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
LogUtils.d("收到群自定义消息:群组 " + groupID + "" + sender.getNickName());
LogUtils.d("收到群自定义消息:群组 " + groupID + "" + sender.getNickName() +",mRoomId:"+mRoomId);
if (!groupID.equals("")) {
String message = new String(customData, StandardCharsets.UTF_8);
RoomMessageEvent event = GsonUtils.fromJson(message, RoomMessageEvent.class);
notifyMessageReceived(event);
LogUtils.d("收到群自定义消息(信令):", message);
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);

View File

@@ -58,21 +58,11 @@ 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

@@ -32,6 +32,8 @@ public class RewardGiftContacts {
void getGiftPack(String s);
void getGiftPackListCount(GiftPackListCount giftPackListCount);
void roomHotCard();
}
public interface IIndexPre extends IPresenter {
@@ -43,7 +45,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);
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 wallet();
@@ -51,11 +53,13 @@ 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);
void roomAuctionJoin(String auction_id,String user_id, String gift_id, String num,String type,String gift_bag_id);
void giftPack();
void getGiftPack(String roomId,String userId,String heart_id,String auction_id );
void getGiftPackListCount();
void roomHotCard(String udid,String room_id,String num);
}
}

View File

@@ -46,8 +46,8 @@ public class RewardGiftPresenter extends BasePresenter<RewardGiftContacts.View>
}
@Override
public void getGiftLabel(String have_hot) {
RetrofitClient.getInstance().getGiftLabel(have_hot, new BaseObserver<List<GiftLabelBean>>() {
public void getGiftLabel(String type) {
RetrofitClient.getInstance().getGiftLabel(type, new BaseObserver<List<GiftLabelBean>>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
@@ -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) {
RetrofitClient.getInstance().roomGift(room_id, gift_id, gift_num, to_uid, type, pit_number, heart_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,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>() {
@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) {
RetrofitClient.getInstance().roomAuctionJoin(auction_id, user_id, gift_id, num, type, new BaseObserver<RoomAuction.AuctionListBean>() {
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>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
@@ -208,9 +208,6 @@ public class RewardGiftPresenter extends BasePresenter<RewardGiftContacts.View>
if (MvpRef == null) {
MvpRef = new WeakReference<>(mView);
}
if (giftPackBeans == null) {
return;
}
MvpRef.get().giftPack(giftPackBeans);
}
});
@@ -255,4 +252,23 @@ public class RewardGiftPresenter extends BasePresenter<RewardGiftContacts.View>
}
});
}
@Override
public void roomHotCard(String udid, String room_id, String num) {
RetrofitClient.getInstance().roomHotCard(udid, room_id, num, new BaseObserver<String>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
}
@Override
public void onNext(String s) {
if (MvpRef == null) {
MvpRef = new WeakReference<>(mView);
}
MvpRef.get().roomHotCard();
}
});
}
}

View File

@@ -18,6 +18,8 @@ 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;
@@ -54,7 +56,9 @@ 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;
@@ -90,7 +94,7 @@ import io.reactivex.disposables.Disposable;
public class AgoraManager {
private static volatile AgoraManager instance;
public RtcEngineEx rtcEngine;
public RtcEngineEx rtcEngine;
// private RtcEngineEx rtcEngineEx;
private Context context;
private boolean isLocalAudioEnabled = true; // 默认开启麦克风
@@ -103,7 +107,7 @@ public class AgoraManager {
private static List<Music> musicList;
private static boolean isBjMusic = false;
private static List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private static ChannelMediaOptions options;
private static RtcConnection connection;
private String pkRoomId = "";
@@ -120,6 +124,12 @@ 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;
}
@@ -187,7 +197,7 @@ public class AgoraManager {
config.mAppId = appId;
config.mEventHandler = getDefaultEventHandler();
config.mChannelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
config.mAudioScenario = Constants.AUDIO_SCENARIO_CHORUS;
config.mAudioScenario = Constants.AUDIO_SCENARIO_GAME_STREAMING;
config.mAreaCode = 1;
rtcEngine = (RtcEngineEx) RtcEngine.create(config);
@@ -200,7 +210,7 @@ public class AgoraManager {
try {
rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO,
Constants.AUDIO_SCENARIO_GAME_STREAMING);
rtcEngine.enableAudioVolumeIndication(200, 3, true);
rtcEngine.enableAudioVolumeIndication(500, 3, true);
rtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
rtcEngine.muteLocalAudioStream(true); // 默认静音
rtcEngine.muteAllRemoteAudioStreams(false); // 监听远端的音频
@@ -220,6 +230,9 @@ public class AgoraManager {
"}" +
"}");
rtcEngine.setParameters("{\"che.video.mobile_1080p\":true}");
setEnable();
} catch (Exception e) {
LogUtils.w("AgoraManager", "Failed to set parameters", e);
}
@@ -232,6 +245,7 @@ public class AgoraManager {
}
}
}
public static int calculateScreenAngle(int orientation) {
if (orientation >= 315 || orientation < 45) {
return 0; // 竖屏0度
@@ -243,6 +257,7 @@ public class AgoraManager {
return 270; // 横屏左270度
}
}
/**
* 加入语音聊天房间
*/
@@ -271,6 +286,7 @@ public class AgoraManager {
// 在频道中发布屏幕采集的音频
options.publishScreenCaptureAudio = true;
ClientRole(isCamerJs);
// options.publishMediaPlayerId = 0;
rtcEngine.joinChannel(token, mRoomId, uid, options);
@@ -279,6 +295,18 @@ public class AgoraManager {
}
public void setEnable(){
if (SpUtil.getSkService()==1){
rtcEngine.setParameters("{\"che.audio.aec.enable\":false}"); // 关闭回音消除
rtcEngine.setParameters("{\"che.audio.ans.enable\":false}"); // 关闭降噪
rtcEngine.setParameters("{\"che.audio.agc.enable\":false}"); // 关闭增益控制
}else {
rtcEngine.setParameters("{\"che.audio.aec.enable\":true}"); // 开启回音消除
rtcEngine.setParameters("{\"che.audio.ans.enable\":true}"); // 开启降噪
rtcEngine.setParameters("{\"che.audio.agc.enable\":true}"); // 开启增益控制
}
}
/**
* 清理资源但保留实例
*/
@@ -332,14 +360,14 @@ public class AgoraManager {
}
handlers.clear();
}
if (disposableA != null && !disposableA.isDisposed()){
if (disposableA != null && !disposableA.isDisposed()) {
disposableA.dispose();
}
if (disposableB != null && !disposableB.isDisposed()){
disposableB.dispose();
if (disposableB != null && !disposableB.isDisposed()) {
disposableB.dispose();
}
if (disposableC != null && !disposableC.isDisposed()){
disposableC.dispose();
if (disposableC != null && !disposableC.isDisposed()) {
disposableC.dispose();
}
// 关闭线程池
if (executorService != null && !executorService.isShutdown()) {
@@ -396,14 +424,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);
if (state == 0) {
// LogUtils.e("onRemoteAudioStateChanged", "uid------>" + uid, "state------>" + state, "reason------>" + reason, "elapsed------>" + elapsed);
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
// Pk 关闭远端推流
@@ -416,7 +444,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
@@ -475,7 +503,7 @@ public class AgoraManager {
@Override
public void onLyricResult(String requestId, long songCode, String lyricUrl, int reason) {
if (lyricUrl != null) {
LogUtils.e("roomInfoEvent",lyricUrl);
LogUtils.e("roomInfoEvent", lyricUrl);
getLyricsInstance(lyricUrl);
}
}
@@ -549,17 +577,31 @@ public class AgoraManager {
if (speakers == null || speakers.length == 0) return;
for (final AudioVolumeInfo info : speakers) {
final int uid = info.uid;
final int volume = info.volume;
// 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 (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
ThreadUtils.runOnUiThread(() -> {
// 远程用户音量变化
listener.onRemoteSoundLevelUpdate(uid > 0 ? String.valueOf(uid) : SpUtil.getUserId() + "", volume);
});
listener.onRemoteSoundLevelUpdate(entry.getKey(), entry.getValue());
}
}
}
@@ -636,6 +678,7 @@ public class AgoraManager {
}
};
}
/**
* 创建并返回 IMediaPlayerObserver 实例
*/
@@ -686,37 +729,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
@@ -733,6 +776,7 @@ public class AgoraManager {
}
};
}
public void potexao(String page) {
ClientRole(true);
rtcEngine.playEffect(1, page, 0, 1, 0, 100, true);
@@ -748,7 +792,7 @@ public class AgoraManager {
}
}
public void joinChannelEx(String token, String channelId, int uid,String pkUserIds) {
public void joinChannelEx(String token, String channelId, int uid, String pkUserIds) {
if (rtcEngine == null) {
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
}
@@ -788,17 +832,17 @@ public class AgoraManager {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
DisplayMetrics outMetrics=new DisplayMetrics();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
// // 设置屏幕采集的参数
screenCaptureParameters.captureVideo = true;
screenCaptureParameters.videoCaptureParameters.width = outMetrics.widthPixels;
screenCaptureParameters.videoCaptureParameters.height = outMetrics.heightPixels;
screenCaptureParameters.videoCaptureParameters.width = outMetrics.widthPixels;
screenCaptureParameters.videoCaptureParameters.height = outMetrics.heightPixels;
screenCaptureParameters.videoCaptureParameters.framerate = 15;
screenCaptureParameters.captureAudio = true;
screenCaptureParameters.audioCaptureParameters.captureSignalVolume =50;
screenCaptureParameters.videoCaptureParameters.contentHint=1 ;
screenCaptureParameters.audioCaptureParameters.captureSignalVolume = 50;
screenCaptureParameters.videoCaptureParameters.contentHint = 1;
rtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VD_1280x720,
FRAME_RATE_FPS_15,
@@ -811,12 +855,12 @@ public class AgoraManager {
}
public void setExternalMediaProjection(MediaProjection[] mediaProjection){
public void setExternalMediaProjection(MediaProjection[] mediaProjection) {
rtcEngine.setExternalMediaProjection(mediaProjection[0]);
}
public void isPost(){
if (rtcEngine != null){
public void isPost() {
if (rtcEngine != null) {
ScreenCaptureParameters screenCaptureParameters = new ScreenCaptureParameters();
// 设置新的屏幕共享参数
@@ -895,6 +939,7 @@ public class AgoraManager {
}
}
}
//关闭对方的所有推流
public void muteAllRemoteAudioStreamsEx(boolean enabled) {
if (rtcEngine == null) {
@@ -910,10 +955,11 @@ public class AgoraManager {
// rtcEngine.muteAllRemoteAudioStreamsEx(enabled, connection);
}
}
//打开对方支持的推流
public void muteAllRemoteAudioStreamsExUserId(boolean enabled){
if (rtcEngine != null){
rtcEngine.muteRemoteAudioStreamEx(pkUserId,enabled,connection);
public void muteAllRemoteAudioStreamsExUserId(boolean enabled) {
if (rtcEngine != null) {
rtcEngine.muteRemoteAudioStreamEx(pkUserId, enabled, connection);
}
}
@@ -989,6 +1035,7 @@ public class AgoraManager {
// }
// }
public void addSoundLevelListener(SoundLevelUpdateListener listener) {
LogUtils.e("AgoraManager", "addSoundLevelListener: " + listener + "============" + soundLevelUpdateListeners.size());
if (soundLevelUpdateListeners != null) {
soundLevelUpdateListeners.add(listener);
}
@@ -1000,10 +1047,24 @@ 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);
}
@@ -1075,8 +1136,8 @@ public class AgoraManager {
String result = musicContentCenter.preload(mSongCode);
// 使用后台线程池处理预加载检查避免阻塞UI线程
disposableC = Observable.timer(3000, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> {
isPreload(mSongCode, type);
});
isPreload(mSongCode, type);
});
} else {
try {
musicPlayer.open(mSongCode, 0);
@@ -1225,15 +1286,17 @@ public class AgoraManager {
public void setPlayoutVolume(int volume) {
if (musicPlayer != null) {
musicPlayer.adjustPlayoutVolume(volume);//调节本地播放音量。 参数是0-100
musicPlayer.adjustPublishSignalVolume(volume*2);//调节远端用户听到的音量。 参数是0-400
musicPlayer.adjustPublishSignalVolume(volume * 2);//调节远端用户听到的音量。 参数是0-400
}
}
/**
* 伴奏音量
*
* @param volume
*/
public void setAdjustPublishSignalVolume(int volume){
public void setAdjustPublishSignalVolume(int volume) {
musicPlayer.adjustPublishSignalVolume(volume);//调节远端用户听到的音量。 参数是0-400
}
@@ -1325,7 +1388,7 @@ public class AgoraManager {
.build();
if (StatusUtil.isCompleted(task)) {
MusicFileBean musicFileBean = new MusicFileBean();
LogUtils.e("roomInfoEvent",convertFileToByteArray(task.getFile()));
LogUtils.e("roomInfoEvent", convertFileToByteArray(task.getFile()));
musicFileBean.setFileData(convertFileToByteArray(task.getFile()));
EventBus.getDefault().post(musicFileBean);
} else {
@@ -1343,18 +1406,18 @@ 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
public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, @NonNull Listener1Assist.Listener1Model model) {
Logger.e("taskEnd", model);
LogUtils.e("roomInfoEvent",convertFileToByteArray(task.getFile()));
LogUtils.e("roomInfoEvent", convertFileToByteArray(task.getFile()));
MusicFileBean musicFileBean = new MusicFileBean();
musicFileBean.setFileData(convertFileToByteArray(task.getFile()));
EventBus.getDefault().post(musicFileBean);

View File

@@ -35,6 +35,7 @@ public class MqttConnect {
public static String qx_hour_ranking = "";
public static String qx_redpacket_arrive = "";//红包飘屏的主题
public static String qx_xianxuan = "";//炼仙传说推送
Handler handler = new Handler(Looper.getMainLooper());
String[] topic;
int[] qos = {1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 消息质量
@@ -50,12 +51,14 @@ public class MqttConnect {
update_app = "qx_xunlehui"; // 巡乐会飘屏
qx_hour_ranking = "qx_hour_ranking";//小时榜飘屏
qx_redpacket_arrive = "qx_redpacket_arrive"; //红包飘屏的主题
qx_xianxuan = "qx_xianxuan"; //红包飘屏的主题
ArrayList<String> topicList = new ArrayList<>();
topicList.add(shutdown);
topicList.add(update_app);
topicList.add(qx_hour_ranking);
topicList.add(qx_redpacket_arrive);
topicList.add(qx_xianxuan);
topic = topicList.toArray(new String[0]);
}
@@ -93,6 +96,7 @@ public class MqttConnect {
sub(update_app);
sub(qx_hour_ranking);
sub(qx_redpacket_arrive);
sub(qx_xianxuan);
// UI操作回到主线程
ActivityUtils.getTopActivity().runOnUiThread(() -> uiTip("MQTT连接成功"));
@@ -139,8 +143,8 @@ public class MqttConnect {
public void close() {
if (mqttClient != null && mqttClient.isConnected()) {
try {
mqttClient.close();
mqttClient.disconnect();
mqttClient.close();
mqttClient = null;
} catch (MqttException e) {
LogUtils.e(Tag, "关闭MQTT连接报错" + e.getMessage());

View File

@@ -6,9 +6,16 @@ import android.os.Looper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.LogUtils;
import com.google.gson.reflect.TypeToken;
import com.xscm.moduleutil.base.RealTimeMessages;
import com.xscm.moduleutil.base.SocketBean;
import com.xscm.moduleutil.bean.MqttXlhEnd;
import com.xscm.moduleutil.bean.XLHBean;
import com.xscm.moduleutil.bean.room.refining.MonsterEndBean;
import com.xscm.moduleutil.bean.room.refining.MonsterInfoBean;
import com.xscm.moduleutil.bean.room.refining.OpenMonsterBean;
import com.xscm.moduleutil.event.HourlyBean;
import com.xscm.moduleutil.event.RedBean;
import com.xscm.moduleutil.event.RoomGiftRunable;
@@ -59,6 +66,51 @@ public class MqttInitCallback implements MqttCallback {
receiveQXHourRanking(topic, messageStr);
} else if (topic.equals("qx_redpacket_arrive")) {
receiveRed(topic, messageStr);
} else if (topic.equals("qx_xianxuan")) {
receiveXianxuanMessage(messageStr);
}
}
private void receiveXianxuanMessage(String messageStr) {
try {
JSONObject jsonObject = JSON.parseObject(messageStr);
String message = jsonObject.getString("msg");
// 将事件处理放到主线程执行
new Handler(Looper.getMainLooper()).post(() -> {
processXianxuanMessage(message);
});
} catch (Exception e) {
LogUtils.e("MQTT", "解析MQTT消息异常", e);
}
}
private void processXianxuanMessage(String message) {
SocketBean dataList = GsonUtils.fromJson(message, SocketBean.class);
switch (dataList.getCode()) {
case 3031:
RealTimeMessages<MonsterInfoBean> monsterInfo = GsonUtils.fromJson(
message,
new TypeToken<RealTimeMessages<MonsterInfoBean>>() {}.getType()
);
EventBus.getDefault().post(monsterInfo.data);
break;
case 3032:
// RealTimeMessages<OpenMonsterBean> openMonster =
// GsonUtils.fromJson(
// message,
// new TypeToken<RealTimeMessages<OpenMonsterBean>>() {}.getType()
// );
// EventBus.getDefault().post(openMonster.data);
break;
case 3033:
RealTimeMessages<MonsterEndBean> monsterEndBean =
GsonUtils.fromJson(
message,
new TypeToken<RealTimeMessages<MonsterEndBean>>() {}.getType()
);
EventBus.getDefault().post(monsterEndBean.data);
break;
}
}

View File

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

View File

@@ -5,6 +5,9 @@ import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import com.blankj.utilcode.util.ActivityUtils;
import com.xscm.moduleutil.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -69,7 +72,7 @@ public class ColorManager {
// 解析颜色为int值
public int getPrimaryColorInt() {
try {
return Color.parseColor(primaryColor);
return UtilConfig.getAttrColor(ActivityUtils.getTopActivity(), R.attr.app_color_colorPrimary);//Color.parseColor(primaryColor);
} catch (Exception e) {
return Color.parseColor("#3ABC6D"); // 默认颜色
}

View File

@@ -0,0 +1,62 @@
package com.xscm.moduleutil.utils
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.text.DecimalFormat
object CountDownUtil {
/**
* 倒计时的实现
*/
fun countDown(lifecycleScope: LifecycleCoroutineScope,
time: Int = 5,
start: (scop: CoroutineScope) -> Unit,
end: () -> Unit,
next: (time: Int) -> Unit
) {
lifecycleScope.launch {
// 在这个范围内启动的协程会在Lifecycle被销毁的时候自动取消
flow {
(time downTo 0).forEach {
delay(1000)
emit(it)
}
}.onStart {
// 倒计时开始 在这里可以让Button 禁止点击状态
start(this@launch)
}.onCompletion {
// 倒计时结束 在这里可以让Button 恢复点击状态
end()
}.catch {
//错误
// YYLogUtils.e(it.message ?: "Unkown Error")
}.collect {
// 在这里 更新值来显示到UI
next(it)
}
}
}
fun formatCountDownTime(milliseconds: Long): String {
val sb = StringBuilder()
val mss = milliseconds * 1000 / 1000
val days = mss / (60 * 60 * 24)
val hours = mss % (60 * 60 * 24) / (60 * 60)
val minutes = mss % (60 * 60) / 60
val seconds = mss % 60
val format = DecimalFormat("00")
if (days > 0 || hours > 0) {
sb.append(format.format(hours)).append(":").append(format.format(minutes)).append(":")
.append(format.format(seconds))
} else {
sb.append(format.format(minutes)).append(":").append(format.format(seconds))
}
return sb.toString()
}
}

View File

@@ -5,4 +5,6 @@ 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,7 +9,6 @@ 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;
@@ -230,14 +229,14 @@ public class DownloadUtil {
}
}
if (TextUtils.isEmpty(mApkPath)) {
Log.e(TAG, "downloadApk: 存储路径为空了");
LogUtils.e(TAG, "downloadApk: 存储路径为空了");
return;
}
//建立一个文件
mFile = new File(mApkPath);
if (FileUtils.createFileByDeleteOldFile(mFile)) {
if (mApi == null) {
Log.e(TAG, "downloadApk: 下载接口为空了");
LogUtils.e(TAG, "downloadApk: 下载接口为空了");
return;
}
mCall = mApi.downloadFile(url);
@@ -284,7 +283,7 @@ public class DownloadUtil {
while ((len = is.read(buff)) != -1) {
os.write(buff, 0, len);
currentLength += len;
Log.e(TAG, "当前进度: " + currentLength);
LogUtils.e(TAG, "当前进度: " + currentLength);
long finalCurrentLength = currentLength;
HANDLER.post(new Runnable() {
@Override

View File

@@ -9,17 +9,28 @@ import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.blankj.utilcode.util.LogUtils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
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.RequestListener;
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;
@@ -33,25 +44,164 @@ 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(options).error(com.xscm.moduleutil.R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
Glide.with(context).load(url).apply(options).apply(createUrlOnlyOptions(url)).error(com.xscm.moduleutil.R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(view);
}
public static void loadHead(ImageView view, String url) {
RequestOptions options = RequestOptions.circleCropTransform();
Glide.with(view).load(url).apply(options).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
Glide.with(view).load(url).apply(options).apply(createUrlOnlyOptions(url)).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(view);
}
public static void loadImage(ImageView view, String url) {
Glide.with(view).load(url).error(R.mipmap.default_image).placeholder(R.mipmap.default_image).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
RequestOptions options = RequestOptions.circleCropTransform();
Glide.with(view).load(url).apply(options).apply(createUrlOnlyOptions(url)).error(R.mipmap.default_image).placeholder(R.mipmap.default_image)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(view);
}
public static void loadImage(Context context, ImageView view, String url) {
Glide.with(context).load(url).error(R.mipmap.default_image).placeholder(R.mipmap.default_image)
.diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
Glide.with(context).load(url).apply(createUrlOnlyOptions(url)).error(R.mipmap.default_image).placeholder(R.mipmap.default_image)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(view);
}
/**
* 加载图片并灰度
@@ -62,13 +212,79 @@ 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.ALL).into(view);
.error(R.mipmap.default_image).placeholder(R.mipmap.default_image).diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(view);
}
// 可调节灰度程度的方法
public static void loadGrayscaleImage(Context context, String url, ImageView imageView, float saturation) {
Glide.with(context)
.load(url)
.apply(RequestOptions.bitmapTransform(new GrayscaleTransformation(saturation)))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
})
.into(imageView);
}
@@ -78,7 +294,7 @@ public class ImageLoader {
} else {
view.setVisibility(View.VISIBLE);
}
Glide.with(context).load(url).diskCacheStrategy(DiskCacheStrategy.ALL).into(view);
Glide.with(context).load(url).diskCacheStrategy(DiskCacheStrategy.RESOURCE).into(view);
}
}

View File

@@ -14,6 +14,7 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
@@ -26,13 +27,21 @@ 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.LogUtils;
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;
@@ -70,11 +79,54 @@ 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)
.error(new ColorDrawable(Color.TRANSPARENT)); // 透明错误图;
// 禁止尺寸影响缓存
// .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}
/**
* 默认加载
*/
public static void loadImageView(String path, ImageView mImageView) {
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(mImageView);
}
/**
@@ -82,7 +134,40 @@ public class ImageUtils {
*/
public static void loadIcon(String path, ImageView mImageView) {
mImageView.setVisibility(TextUtils.isEmpty(path) ? GONE : View.VISIBLE);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(mImageView);
}
/**
@@ -101,8 +186,41 @@ 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.ALL);
Glide.with(mImageView).load(path).apply(options).into(mImageView);
RequestOptions options = new RequestOptions().override(width, height).diskCacheStrategy(DiskCacheStrategy.RESOURCE);
Glide.with(mImageView).load(path).apply(options)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(mImageView);
}
/**
@@ -136,7 +254,9 @@ 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文件
@@ -155,7 +275,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) {
@@ -179,7 +299,8 @@ 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;
}
@@ -191,7 +312,40 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).error(errorRes).placeholder(errorRes).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path)).error(errorRes).
placeholder(errorRes).centerCrop().listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:", e);
return false;
}
}).thumbnail(0.3f).into(mImageView);
}
@@ -207,7 +361,41 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path))
.placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:"+path, e);
return false;
}
}).thumbnail(0.3f).into(mImageView);
}
public static void loadHeadCC(String path, ImageView mImageView) {
@@ -221,7 +409,42 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).asBitmap().load(path)
.apply(createUrlOnlyOptions(path)).listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model,
Target<Bitmap> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Bitmap> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:"+path, e);
return false;
}
})
.error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).centerCrop()
.thumbnail(0.3f).into(mImageView);
}
public static void loadHead(String path, ImageView mImageView) {
@@ -235,7 +458,40 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:"+path, e);
return false;
}
}) .thumbnail(0.3f).into(mImageView);
}
public static void loadHeadCC(String path, ImageView mImageView, LinearLayout.LayoutParams params) {
@@ -249,8 +505,9 @@ public class ImageUtils {
return;
}
}
Glide.with(mImageView).asBitmap().load(path).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
.diskCacheStrategy(DiskCacheStrategy.ALL)
Glide.with(mImageView).asBitmap().load(path)
.apply(createUrlOnlyOptions(path))
.error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
// 添加加载监听
.listener(new RequestListener<Bitmap>() {
@Override
@@ -262,10 +519,29 @@ public class ImageUtils {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
// 加载成功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
@@ -283,22 +559,87 @@ public class ImageUtils {
}
public static void loadCenterCrop(String path, ImageView mImageView) {
Glide.with(mImageView).load(path).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).apply(createUrlOnlyOptions(path)).centerCrop()
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:"+path, e);
return false;
}
}).into(mImageView);
}
public static void loadRes(int path, ImageView mImageView) {
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onResourceReady(Drawable resource, Object model,
Target<Drawable> target, DataSource dataSource,
boolean isFirstResource) {
// dataSource 是关键参数!
switch (dataSource) {
case DATA_DISK_CACHE:
case RESOURCE_DISK_CACHE:
LogUtils.e("GlideCache", "来自磁盘缓存");
break;
case MEMORY_CACHE:
LogUtils.e("GlideCache", "来自内存缓存");
break;
case LOCAL: // 本地文件
LogUtils.e("GlideCache", "来自本地文件");
break;
case REMOTE: // 网络下载
LogUtils.e("GlideCache", "来自网络下载");
break;
default:
LogUtils.e("GlideCache", "来自: " + dataSource);
}
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
Target<Drawable> target, boolean isFirstResource) {
Log.e("GlideCache", "加载失败"+"path:"+path, e);
return false;
}
}).into(mImageView);
}
/**
* 加载图片(优先使用本地缓存,无缓存则下载)
*
* @param context 上下文
* @param url 图片 URL
* @param url 图片 URL
* @param imageView 目标 ImageView
*/
public static void loadImageWithCache(Context context, String url, ImageView imageView) {
public static void loadImageWithCache(String url, ImageView imageView) {
if (TextUtils.isEmpty(url)) return;
// 去掉动态参数,提取稳定 URL
@@ -306,9 +647,9 @@ public class ImageUtils {
String signature = Md5Utils.getMD5String(stableUrl); // 使用 MD5 生成唯一签名
// Glide 加载配置
Glide.with(context)
Glide.with(imageView)
.load(stableUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL) // 缓存所有版本
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) // 缓存所有版本
.signature(new ObjectKey(signature)) // 使用签名确保缓存一致
.placeholder(R.mipmap.room_bj) // 加载中占位图
.error(R.mipmap.room_bj) // 加载失败占位图
@@ -427,7 +768,7 @@ public class ImageUtils {
* @param listener 回调
*/
public static void loadBitmap(String path, final onLoadBitmap listener) {
Glide.with(Utils.getApp()).asBitmap().load(path).into(new SimpleTarget<Bitmap>() {
Glide.with(Utils.getApp()).asBitmap().load(path).apply(createUrlOnlyOptions(path)).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
@@ -466,7 +807,8 @@ 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
@@ -490,6 +832,7 @@ public class ImageUtils {
Glide.with(imageView.getContext())
.asBitmap()
.load(url)
.apply(createUrlOnlyOptions(url))
.error(defaultResId) // 加载失败时显示默认图片
.into(new SimpleTarget<Bitmap>() {
@Override
@@ -519,8 +862,6 @@ public class ImageUtils {
}
/**
* 加载bitmap回调
*/
@@ -598,12 +939,13 @@ 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;
@@ -655,7 +997,55 @@ public class ImageUtils {
}
}
public static void clearDiskCache(Context context){
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) {
Glide.get(context).clearDiskCache();
}

View File

@@ -13,6 +13,10 @@ import com.xscm.moduleutil.R;
import com.xscm.moduleutil.utils.logger.Logger;
import com.xscm.moduleutil.widget.AvatarFrameView;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
/**
* 描述 设置中的用户头像
@@ -58,7 +62,10 @@ public class MeHeadView extends ConstraintLayout {
mIvFrame.setVisibility(GONE);
} else {
mIvFrame.setVisibility(VISIBLE);
mIvFrame.setSource(framePicture, 1);
mIvFrame.stopPlay();
Observable.timer(200, TimeUnit.MILLISECONDS).subscribe(aLong -> {
mIvFrame.setSource(framePicture, 1);
});
}
if (nobilityImage != null && !TextUtils.isEmpty(nobilityImage)) {
@@ -100,6 +107,7 @@ public class MeHeadView extends ConstraintLayout {
/**
* 设置头像,性别,头像框,贵族
*
* @param sex
* @param headPicture
* @param framePicture

View File

@@ -2,8 +2,12 @@ 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;
@@ -50,15 +54,16 @@ public class QXRedPacketManager {
*
* @param redPackets 红包模型列表
*/
public void addRedPackets(List<RedPacketInfo> redPackets) {
public void addRedPackets(String roomId,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) {
@@ -71,17 +76,18 @@ public class QXRedPacketManager {
*
* @param redPacket 红包模型
*/
public void addRedPacket(RedPacketInfo redPacket) {
public void addRedPacket(String roomId,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) {
((QXRedPacketManagerDelegate) this.delegate).onRedPacketAdded(redPacket, this.redPackets.size());
this.delegate.onRedPacketAdded(redPacket, this.redPackets.size());
}
}
@@ -90,11 +96,19 @@ public class QXRedPacketManager {
*
* @param packetId 红包ID
*/
public void removeRedPacket(String packetId) {
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;
}
}
}
this.redPackets.remove(packetId);
if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) {
((QXRedPacketManagerDelegate) this.delegate).onRedPacketRemoved(packetId, this.redPackets.size());
this.delegate.onRedPacketRemoved(packetId, this.redPackets.size());
}
}
@@ -150,7 +164,6 @@ 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) {
@@ -159,11 +172,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;
}
@@ -180,6 +193,10 @@ public class QXRedPacketManager {
((QXRedPacketManagerDelegate) this.delegate).onRedPacketUpdated(packet, this.redPackets.size());
}
}
if (packetTime <= 0) {
removeRedPacket(0,packet.getRedpacket_id());
}
}
// 继续执行定时任务

View File

@@ -18,6 +18,7 @@ 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";
@@ -31,7 +32,9 @@ 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 SHELF = "shelf";//是否打开趣味玩法
public static final String TASK_SERVICE="taskService";//切换服务器
}

View File

@@ -8,6 +8,7 @@ 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;
@@ -233,6 +234,16 @@ 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);
}
@@ -335,6 +346,23 @@ 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);
}
public static int setSkService(int taskService){
SPUtils.getInstance(SPConstants.PREFERENCE_NAME).put("skService", taskService);
return taskService;
}
public static int getSkService(){
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getInt("skService");
}
//获取SharedPreferences音乐轮播方式
public static int getPlayPattern() {
return SPUtils.getInstance(SPConstants.PREFERENCE_NAME).getInt(SPConstants.PLAY_MODE, 1);
@@ -370,6 +398,14 @@ 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

@@ -4,8 +4,8 @@ import android.content.Context;
import android.os.Build;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.DeviceUtils;
import com.blankj.utilcode.util.MetaDataUtils;
import com.chad.library.BuildConfig;
import com.xscm.moduleutil.base.CommonAppContext;
import com.xscm.moduleutil.utils.config.ConfigUtils;
@@ -78,7 +78,8 @@ public class SystemUtils {
}
public static String getShortClientID(Context context) {
String cid = getClientID("xqipaoandroid");
// String cid = getClientID("xqipaoandroid");
String cid = DeviceUtils.getUniqueDeviceId();
return Md5Utils.get(cid + getUUID(context));
}
@@ -90,7 +91,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) {
if (system_config_uuid == null || system_config_uuid.isEmpty()) {
// system_config_uuid = DeviceUtils.getUniqueDeviceId();
configUtils.addOrUpdateText(system_uuid_key, system_config_uuid);
}
@@ -106,9 +107,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("appVersion", BuildConfig.VERSION_NAME + "." + BuildConfig.VERSION_CODE);
headers.put("versionName", BuildConfig.VERSION_NAME);
headers.put("versionCode", String.valueOf(BuildConfig.VERSION_CODE));
headers.put("appId", CommonAppContext.getInstance().appId);
headers.put("versionName", CommonAppContext.getInstance().appVersionName);
headers.put("versionCode", CommonAppContext.getInstance().appVersionCode);
headers.put("system", "android");
headers.put("emulator", CommonAppContext.getInstance().emulator);
headers.put("deviceName", SystemUtils.getDeviceBrand() + SystemUtils.getSystemModel() + SystemUtils.getSystemVersion());

View File

@@ -0,0 +1,142 @@
package com.xscm.moduleutil.utils
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.speech.tts.TextToSpeech
import android.speech.tts.UtteranceProgressListener
import java.util.LinkedList
import java.util.Locale
/**
* 项目名称:羽声语音
* 时间2025/12/6 11:00
* 用途:
*/
class TTSManager private constructor(context: Context) :
TextToSpeech.OnInitListener {
companion object {
@Volatile
private var instance: TTSManager? = null
fun getInstance(context: Context): TTSManager {
return instance ?: synchronized(this) {
instance ?: TTSManager(context.applicationContext).also {
instance = it
}
}
}
}
private var tts: TextToSpeech? = null
private var isInitialized = false
private val pendingQueue = LinkedList<String>()
private var currentLanguage = Locale.CHINESE
init {
initTTS(context)
}
private fun initTTS(context: Context) {
tts = TextToSpeech(context, this).apply {
setOnUtteranceProgressListener(object : UtteranceProgressListener() {
override fun onStart(utteranceId: String?) {
// 开始朗读
}
override fun onDone(utteranceId: String?) {
// 朗读完成
}
override fun onError(utteranceId: String?) {
// 发生错误
}
})
}
}
override fun onInit(status: Int) {
isInitialized = if (status == TextToSpeech.SUCCESS) {
setLanguage(currentLanguage)
true
} else {
false
}
if (isInitialized) {
processPendingQueue()
}
}
fun speak(text: String, flush: Boolean = true) {
if (!isInitialized || tts == null) {
pendingQueue.add(text)
return
}
val utteranceId = System.currentTimeMillis().toString()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val params = Bundle().apply {
putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId)
}
tts?.speak(text,
if (flush) TextToSpeech.QUEUE_FLUSH else TextToSpeech.QUEUE_ADD,
params,
utteranceId)
} else {
@Suppress("DEPRECATION")
val params = HashMap<String, String>()
params[TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID] = utteranceId
tts?.speak(text,
if (flush) TextToSpeech.QUEUE_FLUSH else TextToSpeech.QUEUE_ADD,
params)
}
}
fun setLanguage(locale: Locale): Boolean {
currentLanguage = locale
return if (isInitialized) {
tts?.setLanguage(locale) == TextToSpeech.LANG_COUNTRY_AVAILABLE
} else {
false
}
}
fun stop() {
tts?.stop()
}
fun pause() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts?.stop()
}
}
fun resume() {
// 根据需要实现
}
fun setSpeechRate(rate: Float) {
tts?.setSpeechRate(rate)
}
fun setPitch(pitch: Float) {
tts?.setPitch(pitch)
}
private fun processPendingQueue() {
while (pendingQueue.isNotEmpty()) {
speak(pendingQueue.poll())
}
}
fun release() {
tts?.stop()
tts?.shutdown()
tts = null
isInitialized = false
instance = null
}
}

View File

@@ -168,4 +168,28 @@ 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("yyyy_MM_dd_hh_mm_ss_SSS");
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddhhmmssSSS");
return sf.format(d);
}
/**

View File

@@ -1,6 +1,8 @@
package com.xscm.moduleutil.utils;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import com.lahm.library.EasyProtectorLib;
import com.lahm.library.EmulatorCheckCallback;
@@ -50,4 +52,31 @@ public class UtilConfig {
public static void setSalt(String salt) {
UtilConfig.salt = salt;
}
public static int getAttBg(Context context, int attr){
// 1. 定义需要获取的自定义属性数组
int[] attrs = new int[]{attr};
// 2. 从Context的Theme中获取TypedArray核心绑定当前主题的属性值
TypedArray ta = context.obtainStyledAttributes(attrs);
// 3. 获取attr对应的资源ID默认值0无有效资源时返回0
int bgResId = ta.getResourceId(0, 0);
// 4. 关键手动回收TypedArray释放系统资源避免内存泄漏
ta.recycle();
// 5. 有有效资源ID时设置背景
return bgResId;
}
// 新增:解析自定义颜色属性,返回实际颜色码(核心)
public static int getAttrColor(Context context, int colorAttrId) {
if (context == null) {
return Color.BLACK; // 上下文为空时返回默认黑色,可自定义
}
// 从主题中获取TypedArray解析颜色属性
TypedArray ta = context.obtainStyledAttributes(new int[]{colorAttrId});
// getColor(索引, 默认颜色)直接返回十六进制颜色码适配setTextColor
int color = ta.getColor(0, Color.BLACK);
ta.recycle(); // 必须回收,避免内存泄漏
return color;
}
}

View File

@@ -0,0 +1,57 @@
package com.voice.lib_base.ext
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.ParameterizedType
/**
* 作者 : QIngNing
* 时间 : 2021/12/21
* 描述 :
*/
@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> AppCompatActivity.inflateBindingWithGeneric(layoutInflater: LayoutInflater): VB =
withGenericBindingClass<VB>(this) { clazz ->
clazz.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB
}.also { binding ->
if (binding is ViewDataBinding) {
binding.lifecycleOwner = this
}
}
@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> Fragment.inflateBindingWithGeneric(layoutInflater: LayoutInflater, parent: ViewGroup?, attachToParent: Boolean): VB =
withGenericBindingClass<VB>(this) { clazz ->
clazz.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)
.invoke(null, layoutInflater, parent, attachToParent) as VB
}.also { binding ->
if (binding is ViewDataBinding) {
binding.lifecycleOwner = viewLifecycleOwner
}
}
private fun <VB : ViewBinding> withGenericBindingClass(any: Any, block: (Class<VB>) -> VB): VB {
var genericSuperclass = any.javaClass.genericSuperclass
var superclass = any.javaClass.superclass
while (superclass != null) {
if (genericSuperclass is ParameterizedType) {
try {
return block.invoke(genericSuperclass.actualTypeArguments[0] as Class<VB>)
} catch (e: NoSuchMethodException) {
} catch (e: ClassCastException) {
} catch (e: InvocationTargetException) {
throw e.targetException
}
}
genericSuperclass = superclass.genericSuperclass
superclass = superclass.superclass
}
throw IllegalArgumentException("There is no generic of ViewBinding.")
}

View File

@@ -5,6 +5,7 @@ import android.content.SharedPreferences;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class ConfigUtils {
@@ -74,8 +75,11 @@ 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).toString();
return data_list.get(key)!=null?data_list.get(key).toString():"";
else
return sp.getString(key, null);
}

View File

@@ -15,10 +15,52 @@ public enum EnvironmentEnum {
1600096860,
"3e8f3add448d4692bc1d04c75ffe801b",
//"tcp://1.13.101.98",
"tcp://1.13.20.30",
// "tcp://1.13.20.30",
"tcp://yushengapi.qxyushen.top",
// "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=",
@@ -30,7 +72,8 @@ public enum EnvironmentEnum {
"wxc7681513be9f926b",
1600096890,
"02f7339ec98947deaeab173599891932",
"tcp://1.13.181.248",
// "tcp://1.13.181.248",
"tcp://test.vespa.qxyushen.top",
"https://test.vespa.qxyushen.top/h5",
1);

View File

@@ -9,6 +9,7 @@ import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import okhttp3.Connection;
@@ -54,24 +55,25 @@ public class DataLoggingInterceptor implements Interceptor {
logger.reset();
logger.log(sLogStartFlag);
logger.log(sFormatLine);
// logger.log("2\n"+sFormatLine);
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
Connection connection = chain.connection();
Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
String requestStartMessage = request.method() + " " + request.url() + " " + protocol;
logger.log(requestStartMessage);
// request.url().encodedPath() 这是只展示最后的url地址没有带有前面的https对应的域名只是展示路径
String requestStartMessage = request.method() + " " + Arrays.toString(request.url().encodedPath().split("/api/")) + " " + protocol;
// logger.log("3\n"+requestStartMessage);
if (hasRequestBody) {
// Request body headers are only present when installed as a network interceptor. Force
// them to be included (when available) so there values are known.
if (requestBody.contentType() != null) {
logger.log("Content-Type: " + requestBody.contentType());
// logger.log("4\n"+ "Content-Type: " + requestBody.contentType());
}
if (requestBody.contentLength() != -1) {
logger.log("Content-Length: " + requestBody.contentLength());
// logger.log("5\n"+"Content-Length: " + requestBody.contentLength());
}
}
@@ -80,14 +82,14 @@ public class DataLoggingInterceptor implements Interceptor {
String name = rHeaders.name(i);
// Skip headers from the request body as they are explicitly logged above.
if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
logger.log(name + ": " + rHeaders.value(i));
// logger.log("6\n"+name + ": " + rHeaders.value(i));
}
}
if (!hasRequestBody) {
logger.log("END " + request.method());
// logger.log("7\n"+"END " + request.method());
} else if (bodyEncoded(request.headers())) {
logger.log("END " + request.method() + " (encoded body omitted)");
// logger.log("8\n"+"END " + request.method() + " (encoded body omitted)");
} else {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
@@ -99,35 +101,35 @@ public class DataLoggingInterceptor implements Interceptor {
}
if (charset != null) {
logger.log(sFormatLine);
// logger.log("9\n"+sFormatLine);
if (isPlaintext(buffer)) {
try {
String requestStr = URLDecoder.decode(buffer.readString(charset), "UTF-8");
String[] strs = requestStr.split("&");
for (String str : strs) {
logger.log(str);
// logger.log("10\n"+str);
}
} catch (Exception e) {
logger.log(buffer.readString(charset));
logger.log("11\n"+buffer.readString(charset));
}
logger.log("END " + request.method()
+ " (" + requestBody.contentLength() + "-byte body)");
// logger.log("12\n"+"END " + request.method()
// + " (" + requestBody.contentLength() + "-byte body)");
} else {
logger.log("END " + request.method() + " (binary "
+ requestBody.contentLength() + "-byte body omitted)");
// logger.log("13\n"+"END " + request.method() + " (binary "
// + requestBody.contentLength() + "-byte body omitted)");
}
}
}
logger.log(sFormatLine);
// logger.log("14\n"+sFormatLine);
long startNs = System.nanoTime();
Response response;
try {
response = chain.proceed(request);
} catch (Exception e) {
logger.log("HTTP FAILED: " + e);
logger.log(sLogEndFlag);
logger.log("15\n"+"HTTP FAILED: " + e);
// logger.log(sLogEndFlag);
throw e;
}
@@ -136,21 +138,19 @@ public class DataLoggingInterceptor implements Interceptor {
if (responseBody != null) {
long contentLength = responseBody.contentLength();
String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
// logger.log(response.code() + " " + response.message() + " "
// + response.request().url() + " (" + tookMs + "ms)");
logger.log(response.code() + " " + response.message() + " "
+ response.request().url() + "" + response.networkResponse().request().url() + " (" + tookMs + "ms)");
logger.log("17\n"+response.code() + " " + response.message() + " "
+ Arrays.toString(response.request().url().encodedPath().split("/api/")) + "" + Arrays.toString(response.networkResponse().request().url().encodedPath().split("/api/")) + " (" + tookMs + "ms)");
Headers headers = response.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
logger.log(headers.name(i) + ": " + headers.value(i));
}
// Headers headers = response.headers();
// for (int i = 0, count = headers.size(); i < count; i++) {
// logger.log("18\n"+headers.name(i) + ": " + headers.value(i));
// }
if (!HttpHeaders.hasBody(response)) {
logger.log("END HTTP");
// logger.log("19\n"+"END HTTP");
} else if (bodyEncoded(response.headers())) {
logger.log("END HTTP (encoded body omitted)");
// logger.log("20\n"+"END HTTP (encoded body omitted)");
} else {
BufferedSource source = responseBody.source();
if (source.isOpen()) {
@@ -164,25 +164,26 @@ public class DataLoggingInterceptor implements Interceptor {
}
if (!isPlaintext(buffer)) {
logger.log("END HTTP (binary " + buffer.size() + "-byte body omitted)");
logger.log(sFormatLine);
// logger.log("21\n"+"END HTTP (binary " + buffer.size() + "-byte body omitted)");
// logger.log("22\n"+sFormatLine);
logger.log(sLogEndFlag);
return response;
}
if (contentLength != 0 && charset != null) {
logger.log(sFormatLine);
logger.log(buffer.clone().readString(charset));
// logger.log("24\n"+sFormatLine);
//这是展示返回的数据日志
// logger.log(buffer.clone().readString(charset));
}
logger.log("END HTTP (" + buffer.size() + "-byte body)");
// logger.log("25\n"+"END HTTP (" + buffer.size() + "-byte body)");
} else {
logger.log("END HTTP");
// logger.log("26\n"+"END HTTP");
}
}
}
logger.log(sFormatLine);
logger.log("27\n"+sFormatLine);
logger.log(sLogEndFlag);
return response;

View File

@@ -178,7 +178,7 @@ public class RoomCPView extends FrameLayout {
// 启动头像上下浮动动画
// startAvatarFloatAnimation();
startAvatarFloatAnimation();
});
}
@@ -193,11 +193,21 @@ public class RoomCPView extends FrameLayout {
LogUtils.e("onFailed", s);
// 确保所有UI操作在主线程中执行
post(() -> {
// 动画失败,隐藏视图
setVisibility(View.GONE);
anim_cp.setVisibility(View.GONE);
// 继续播放下一个
loadStartAnimation();
if (anim_cp != null) {
// 停止头像动画
stopAvatarAnimation();
// 隐藏动画视图和头像
anim_cp.setVisibility(View.GONE);
avatarContainer1.setVisibility(View.GONE);
if (isOnece) {
return;
}
// 通知播放完成
notifyPlaybackComplete();
loadStartAnimation();
}
});
}
});
@@ -274,11 +284,15 @@ public class RoomCPView extends FrameLayout {
post(() -> {
// 设置MP4动画文件
currPlayPath = localPath;
// 启动从底部弹起动画
startBottomUpAnimation();
// 开始播放动画
anim_cp.setLoop(1);
startBottomUpAnimation();
setVisibility(View.VISIBLE);
anim_cp.setVisibility(View.VISIBLE);
avatarContainer1.setVisibility(VISIBLE);
anim_cp.startPlay(new File(currPlayPath));
});
}
@@ -717,11 +731,10 @@ public class RoomCPView extends FrameLayout {
bottomUpAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
setVisibility(View.VISIBLE);
anim_cp.setVisibility(View.VISIBLE);
avatarContainer1.setVisibility(VISIBLE);
anim_cp.startPlay(new File(currPlayPath));
// setVisibility(View.VISIBLE);
// anim_cp.setVisibility(View.VISIBLE);
// avatarContainer1.setVisibility(VISIBLE);
// anim_cp.startPlay(new File(currPlayPath));
}
@Override
@@ -752,12 +765,31 @@ public class RoomCPView extends FrameLayout {
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -0.01f);
avatarsFloatUp.setDuration(900); // 增加动画持续时间,使动画更平滑
avatarsFloatUp.setRepeatCount(Animation.INFINITE);
avatarsFloatUp.setRepeatCount(10);
avatarsFloatUp.setRepeatMode(Animation.REVERSE);
avatarsAnimationSet.addAnimation(avatarsFloatUp);
avatarsParentContainer.startAnimation(avatarsAnimationSet);
// 动画结束后重置位置
avatarsAnimationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (avatarContainer1.getVisibility() == View.VISIBLE) {
avatarContainer1.setVisibility(View.GONE);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
/**

View File

@@ -0,0 +1,131 @@
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,13 +1,11 @@
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;
@@ -16,21 +14,14 @@ 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;
@@ -40,11 +31,8 @@ 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;
@@ -57,9 +45,9 @@ import okhttp3.ResponseBody;
public class AvatarFrameView extends FrameLayout {
private PlaybackManager playbackManager;
private boolean isMute = false;
public void setMute(boolean b) {
this.isMute = b;
}
@@ -68,10 +56,7 @@ 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;
// 添加销毁标记
@@ -79,8 +64,6 @@ 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);
@@ -101,25 +84,10 @@ 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) {
@@ -130,186 +98,51 @@ public class AvatarFrameView extends FrameLayout {
}
return "";
}
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();
});
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);
}
private void processPlayItem(PlayItem item) {
try {
// clearPrevious();
String ext = getFileExtension(item.url);
if ("svga".equalsIgnoreCase(ext)) {
mainHandler.post(() -> {
renderType = RenderType.SVGA;
mType = item.type;
if (mBinding != null && mBinding.playView != null) {
mBinding.playView.setVisibility(View.GONE);
}
loadSVGA(item.url);
});
renderType = RenderType.SVGA;
mType = item.type;
if (mBinding != null) {
mBinding.playView.setVisibility(View.GONE);
}
loadSVGA(item.url);
} else if ("mp4".equalsIgnoreCase(ext)) {
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();
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);
}
}
} 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 && mBinding.playView != null) {
if (mBinding != 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;
@@ -330,12 +163,6 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onFailure(Call call, IOException e) {
LogUtils.e("MP4下载失败: " + e.toString());
mainHandler.post(() -> {
// 检查是否已销毁
if (!isDestroyed) {
onPlaybackComplete();
}
});
}
// 更简单的优化版本
@@ -371,63 +198,36 @@ public class AvatarFrameView extends FrameLayout {
fos.flush();
isTxk = true;
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();
}
});
// 关键在执行UI操作前再次检查是否已销毁
if (downloadedFile.exists()) {
LogUtils.d("@@@@Thread", Thread.currentThread().getName());
playMp4File(downloadedFile); // 使用正确的文件引用
} else {
LogUtils.w(TAG, "View destroyed or file not exist after download");
}
} 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;
LogUtils.e("有缓存");
mainHandler.post(() -> {
// 检查是否已销毁
if (file.exists()) {
LogUtils.e("有缓存:"+file.exists()+"===="+file.getAbsolutePath());
playMp4File(file);
} else {
LogUtils.w(TAG, "有缓存2222222222222");
}
});
// 检查是否已销毁
if (file.exists()) {
LogUtils.e("有缓存:" + file.exists() + "====" + file.getAbsolutePath());
playMp4File(file);
} else {
LogUtils.w(TAG, "有缓存2222222222222");
}
}
}
@@ -436,13 +236,11 @@ public class AvatarFrameView extends FrameLayout {
// 双重检查确保组件未被销毁
if (isDestroyed) {
LogUtils.w(TAG, "Attempt to play MP4 file after view destroyed");
onPlaybackComplete();
return;
}
if (mBinding == null || mBinding.playView == null) {
if (mBinding == null) {
LogUtils.w(TAG, "PlayView is null");
onPlaybackComplete();
return;
}
@@ -453,27 +251,23 @@ 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;
}
@@ -496,7 +290,6 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.stopAnimation();
svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null);
onPlaybackComplete();
}
}
@@ -506,11 +299,8 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onFinished() {
// if (isDestroyed) return;
if (mType == 1) { // 循环播放
// 继续循环播放
} else {
onPlaybackComplete();
}
}
});
@@ -523,10 +313,6 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.startAnimation();
} catch (Exception e) {
LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage());
// isPlaying = false;
// playNextFromQueue();
handlePlaybackComplete();
}
}
@@ -536,13 +322,15 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null);
}
if (svgaSurface2 != null) {
svgaSurface2.stopAnimation();
svgaSurface2.clearAnimation();
svgaSurface.setImageDrawable(null);
}
// 增加空值检查
if (mBinding != null && mBinding.playView != null) {
if (mBinding != null) {
mBinding.playView.stopPlay();
}
}
public void stopPlay(){
// 增加空值检查
if (mBinding != null && mBinding.playView.isRunning()) {
mBinding.playView.stopPlay();
}
}
@@ -566,16 +354,7 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onFinished() {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
// 添加延迟确保状态更新
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
});
} else {
isPlaying = false;
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
}
isPlaying = false;
}
});
// 设置循环次数
@@ -588,21 +367,16 @@ 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()) {
mainHandler.post(() -> handleSVGAComplete(videoItem, url));
handleSVGAComplete(videoItem, url);
} else {
handleSVGAComplete(videoItem, url);
}
@@ -610,32 +384,16 @@ public class AvatarFrameView extends FrameLayout {
@Override
public void onError() {
// if (isDestroyed) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
playNextFromQueue();
});
} else {
isPlaying = false;
playNextFromQueue();
}
isPlaying = false;
}
});
} 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);
@@ -646,6 +404,7 @@ public class AvatarFrameView extends FrameLayout {
if (cachedEntity != null) {
// 使用缓存的实体
playCachedSVGA(cachedEntity);
return;
} else {
// 加载新的SVGA
loadNewSVGA(url);
@@ -653,52 +412,49 @@ 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;
playNextFromQueue();
}
});
svgaSurface.startAnimation();
}
@Override
public void onError() {
isPlaying = false;
playNextFromQueue();
}
});
} 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;
// }
// });
//
// svgaSurface.startAnimation();
// }
//
// @Override
// public void onError() {
// isPlaying = false;
// }
// });
// } catch (Exception e) {
// e.printStackTrace();
// }
}
@@ -716,7 +472,6 @@ public class AvatarFrameView extends FrameLayout {
}
// 隐藏所有视图
// if (playerView != null) playerView.setVisibility(View.GONE);
if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
@@ -750,39 +505,7 @@ public class AvatarFrameView extends FrameLayout {
*/
private void releaseResources() {
LogUtils.d(TAG, "Releasing all resources");
// 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());
}
performUICleanup();
}
/**
@@ -791,31 +514,16 @@ public class AvatarFrameView extends FrameLayout {
private void performUICleanup() {
try {
// 停止并清理播放器
if (mBinding != null && mBinding.playView != null) {
if (mBinding != 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();
@@ -834,86 +542,23 @@ 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;
@@ -923,167 +568,4 @@ 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();
}
}
}

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