Compare commits

...

9 Commits

41 changed files with 2001 additions and 31 deletions

Binary file not shown.

View File

@@ -3,6 +3,8 @@ package com.yizhuan.erban.avroom.activity;
import static android.view.View.VISIBLE;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ALL_SERVICE_GIFT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_BOX;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_FAIRY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEADER_TYPE_GIFT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_GIFT;
@@ -14,6 +16,8 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_ROOM_PK_NOTIFY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -107,6 +111,8 @@ import com.yizhuan.xchat_android_core.im.custom.bean.RoomLuckySeaMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomPKAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomPkBean;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomReceivedLuckyGiftAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTemplateNotifyAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTemplateNotifyMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.TarotAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.TarotMsgBean;
import com.yizhuan.xchat_android_core.initial.InitialModel;
@@ -1285,6 +1291,22 @@ public class AVRoomActivity extends BaseMvpActivity<IAvRoomView, AvRoomPresenter
IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.LUCKY_SEA_GIFT_SERVER_NOTIFY);
}
break;
case CUSTOM_MSG_CRAZY_ZOO://疯狂动物园
if (baseProtocol.getSecond() == CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM) {
RoomLuckySeaAttachment attachment = new RoomLuckySeaAttachment(CUSTOM_MSG_CRAZY_ZOO, CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM);
attachment.setRoomLuckySeaMsgBean(JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomLuckySeaMsgBean.class));
ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment);
IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.CRAZY_ZOO_ALL_ROOM_NOTIFY);
}
break;
case CUSTOM_MSG_TEMPLATE_NOTIFY://通用飘屏
if (baseProtocol.getSecond() == CUSTOM_MSG_TEMPLATE_NOTIFY_ALL) {
RoomTemplateNotifyAttachment attachment = new RoomTemplateNotifyAttachment(CUSTOM_MSG_TEMPLATE_NOTIFY, CUSTOM_MSG_TEMPLATE_NOTIFY_ALL);
attachment.setMsgBean(JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomTemplateNotifyMsgBean.class));
ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment);
IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.TEMPLATE_NOTIFY);
}
break;
case CUSTOM_MSG_LUCKY_GIFT://福袋
if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY || baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) {
RoomReceivedLuckyGiftAttachment attachment = new RoomReceivedLuckyGiftAttachment(CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY);

View File

@@ -16,6 +16,7 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LiveData;
@@ -39,7 +40,9 @@ import com.yizhuan.erban.base.BaseFragment;
import com.yizhuan.erban.databinding.FragmentChatroomGameMainBinding;
import com.yizhuan.erban.friend.view.SelectFriendActivity;
import com.yizhuan.erban.home.helper.OpenRoomHelper;
import com.yizhuan.erban.ui.widget.GiftDialog;
import com.yizhuan.erban.ui.widget.ShareDialog;
import com.yizhuan.erban.ui.widget.UserInfoDialog;
import com.yizhuan.erban.utils.RegexUtil;
import com.yizhuan.xchat_android_core.gift.bean.GiftMultiReceiverInfo;
import com.yizhuan.xchat_android_core.gift.bean.GiftReceiveInfo;
@@ -216,7 +219,17 @@ public class HomePartyFragment extends BaseFragment implements View.OnClickListe
ivRoomShare.setOnClickListener(this);
gameMainBinding.llRoomInfo.setOnClickListener(this);
gameMainBinding.ivBack.setOnClickListener(this);
mRoomEffectView.setShowUserCardAction(s -> {
if (roomFragment instanceof GiftDialog.OnGiftDialogBtnClickListener) {
UserInfoDialog.showNewUserInfoDialog(
mContext,
JavaUtil.str2long(s),
true,
true,
true, (GiftDialog.OnGiftDialogBtnClickListener) roomFragment
);
}
});
mRoomEffectView.setPlayNotifyStateListener(playNotifyStateLiveData);
mRoomEffectView.setOnPlayAnimCallback(new Function0<Boolean>() {
@Override

View File

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
@@ -20,13 +21,18 @@ import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.NonNull
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import androidx.core.util.Consumer
import androidx.lifecycle.MutableLiveData
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.chuhai.utils.UiUtils
import com.chuhai.utils.ktx.setPadding2
import com.coorchice.library.SuperTextView
import com.netease.nim.uikit.common.util.sys.ScreenUtil
import com.netease.nim.uikit.support.glide.GlideApp
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.netease.nimlib.sdk.chatroom.model.ChatRoomNotificationAttachment
import com.opensource.svgaplayer.*
@@ -49,12 +55,14 @@ import com.yizhuan.erban.ui.widget.SimpleAnimListener
import com.yizhuan.erban.ui.widget.dialog.AllServiceGiftGoRoomTipsDialog
import com.yizhuan.erban.ui.widget.dialog.AllServiceGiftGoRoomTipsDialog.Companion.isNeedTips
import com.yizhuan.erban.ui.widget.drawgift.DrawGiftPlayHelper
import com.yizhuan.erban.utils.CommonJumpHelper
import com.yizhuan.erban.utils.MsgBuilder
import com.yizhuan.erban.utils.RegexUtil
import com.yizhuan.erban.utils.SpannableBuilder
import com.yizhuan.xchat_android_constants.XChatConstants
import com.yizhuan.xchat_android_core.auth.AuthModel
import com.yizhuan.xchat_android_core.decoration.car.bean.CarInfo
import com.yizhuan.xchat_android_core.home.bean.BannerInfo
import com.yizhuan.xchat_android_core.im.custom.bean.*
import com.yizhuan.xchat_android_core.manager.AvRoomDataManager
import com.yizhuan.xchat_android_core.manager.IMNetEaseManager
@@ -144,6 +152,15 @@ class RoomEffectView @JvmOverloads constructor(
private var playNotifyStateLiveData: MutableLiveData<Boolean>? = null
private var showUserCardAction: ((String) -> Unit)? = null
private val templateMessageAdapter =
TemplateMessageAdapter(listener = object : TemplateMessageAdapter.Listener {
override fun onShowUserCard(uid: String) {
showUserCardAction?.invoke(uid)
}
})
private var onPlayAnimCallback: (() -> Boolean)? = null
fun setPlayNotifyStateListener(stateLiveData: MutableLiveData<Boolean>) {
this.playNotifyStateLiveData = stateLiveData
@@ -153,6 +170,12 @@ class RoomEffectView @JvmOverloads constructor(
this.onPlayAnimCallback = onPlayAnimCallback
}
fun setShowUserCardAction(call: Consumer<String>) {
this.showUserCardAction = {
call.accept(it)
}
}
@NonNull
private fun isShowingGiftNotify(): Boolean {
return onPlayAnimCallback?.invoke() ?: false
@@ -210,6 +233,18 @@ class RoomEffectView @JvmOverloads constructor(
addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage)
}
RoomEvent.CRAZY_ZOO_ROOM_NOTIFY -> {// 疯狂动物园-房间
addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage)
}
RoomEvent.CRAZY_ZOO_ALL_ROOM_NOTIFY -> {// 疯狂动物园-全服
addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage)
}
RoomEvent.TEMPLATE_NOTIFY -> {// 通用模版飘屏
addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage)
}
RoomEvent.FAIRY_DRAW_GIFT_L4,
RoomEvent.FAIRY_DRAW_GIFT_L5,
RoomEvent.FAIRY_CONVERT_L1,
@@ -306,6 +341,9 @@ class RoomEffectView @JvmOverloads constructor(
if (binding.flPlayNotify.childCount != 0) {
return@subscribe
}
if (binding.flTemplateNotify.childCount != 0) {
return@subscribe
}
if (binding.flLuckyBagNotify.childCount != 0) {
return@subscribe
}
@@ -388,6 +426,28 @@ class RoomEffectView @JvmOverloads constructor(
)
}
RoomEvent.CRAZY_ZOO_ROOM_NOTIFY -> {//疯狂动物园-房间(静态)
playNotifyStateLiveData?.value = true
resetPlayNotifyMargin()
showZooNotify(
messagesPlay.removeAt(0)
)
}
RoomEvent.CRAZY_ZOO_ALL_ROOM_NOTIFY -> {//疯狂动物园-全服(动态)
playNotifyStateLiveData?.value = true
resetPlayNotifyMargin()
showZooNotifyBySVGA(
messagesPlay.removeAt(0)
)
}
RoomEvent.TEMPLATE_NOTIFY -> {//通用模版飘屏
resetPlayNotifyMargin()
showTemplateNotify(
messagesPlay.removeAt(0)
)
}
RoomEvent.FAIRY_DRAW_GIFT_L4,
RoomEvent.FAIRY_DRAW_GIFT_L5,
RoomEvent.FAIRY_CONVERT_L1,
@@ -707,6 +767,205 @@ class RoomEffectView @JvmOverloads constructor(
)
}
private fun showZooNotify(roomPlayBean: RoomPlayBean) {
val chatRoomMessage = roomPlayBean.chatRoomMessage
val attachment = chatRoomMessage.attachment as RoomLuckySeaAttachment
val bean = attachment.roomLuckySeaMsgInfo
val textView =
LayoutInflater.from(mContext)
.inflate(R.layout.layout_room_zoo_notify, null) as TextView
val text = SpannableBuilder()
.append(
ResUtil.getString(R.string.congratulation),
ForegroundColorSpan(Color.WHITE)
)
.append(
bean.nick,
ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_FEF23E))
)
.append(
ResUtil.getString(R.string.in_the_zoo),
ForegroundColorSpan(Color.WHITE)
)
.append(
bean.itemMultiple.toString(),
ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF))
)
.append(
ResUtil.getString(R.string.times_reward_get),
ForegroundColorSpan(Color.WHITE)
)
.append(
bean.diamonds.toString(),
ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF))
)
.append(
ResUtil.getString(R.string.diamond_point),
ForegroundColorSpan(Color.WHITE)
)
textView.text = text.build()
animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify)
binding.flPlayNotify.addView(textView)
textView.startAnimation(animationPlay)
binding.flPlayNotify.postDelayed(
{
playNotifyStateLiveData?.value = false
binding.flPlayNotify.removeView(textView)
},
SHOW_TIME.toLong()
)
}
private fun showTemplateNotify(roomPlayBean: RoomPlayBean) {
val chatRoomMessage = roomPlayBean.chatRoomMessage
val attachment =
chatRoomMessage.attachment as? RoomTemplateNotifyAttachment
val msgBean = attachment?.getTemplateMsg()
val resourceType = msgBean?.resourceType
if (resourceType == "IMAGE") {
showTemplateImageNotify(msgBean)
} else if (resourceType == "SVGA") {
showTemplateSvgaNotify(msgBean)
}
}
private fun showTemplateImageNotify(msgBean: RoomTemplateNotifyMsgBean) {
if (msgBean.resourceType != "IMAGE") {
return
}
val resourceContent = msgBean.resourceContent
if (resourceContent.isNullOrEmpty()) {
return
}
playNotifyStateLiveData?.value = true
val rootView = LayoutInflater.from(mContext)
.inflate(R.layout.layout_room_template_notify_image, null)
val textView = rootView.findViewById<TextView>(R.id.tv_text)
val textSize = msgBean.fontSize?.toFloat() ?: 12f
val textColor =
templateMessageAdapter.parseColor(msgBean.textColor) ?: Color.WHITE
textView.textSize = textSize
textView.setTextColor(textColor)
val bgView = rootView.findViewById<ImageView>(R.id.iv_bg)
val params = ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
binding.flTemplateNotify.addView(rootView, params)
val endAction = {
playNotifyStateLiveData?.value = false
binding.flTemplateNotify.removeView(rootView)
}
GlideApp.with(bgView)
.load(resourceContent).into(object : CustomTarget<Drawable>() {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable>?
) {
templateMessageAdapter.convert(textView, msgBean)
bgView.setImageDrawable(resource)
animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify)
rootView.startAnimation(animationPlay)
val skipType = msgBean.skipType
if (skipType != null) {
val clickAction = View.OnClickListener {
if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) {
showUserCardAction?.invoke(msgBean.skipContent ?: "")
} else {
CommonJumpHelper.bannerJump(context, skipType, msgBean.skipContent)
}
}
rootView.setOnClickListener(clickAction)
textView.setOnClickListener(clickAction)
}
binding.flTemplateNotify.postDelayed(endAction, SHOW_TIME.toLong())
}
override fun onLoadCleared(placeholder: Drawable?) {
endAction.invoke()
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
endAction.invoke()
}
})
}
private fun showTemplateSvgaNotify(msgBean: RoomTemplateNotifyMsgBean) {
if (msgBean.resourceType != "SVGA") {
return
}
val resourceContent = msgBean.resourceContent
if (resourceContent.isNullOrEmpty()) {
return
}
playNotifyStateLiveData?.value = true
val svgaImageView = SVGAImageView(mContext)
val endAction = {
playNotifyStateLiveData?.value = false
binding.flTemplateNotify.removeView(svgaImageView)
}
svgaImageView.loops = 1
svgaImageView.clearsAfterDetached = true
val params = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, 0)
params.dimensionRatio = msgBean.getDimensionRatio() ?: "75:11"
svgaImageView.layoutParams = params
svgaImageView.callback = object : SimpleSvgaCallback() {
override fun onFinished() {
endAction.invoke()
}
}
binding.flTemplateNotify.addView(svgaImageView)
shareParser().decodeFromURL(
URL(resourceContent),
object : SVGAParser.ParseCompletion {
override fun onComplete(videoItem: SVGAVideoEntity) {
val text = templateMessageAdapter.parse(context, msgBean) ?: ""
val textKey = msgBean.getSvgaTextKey()
val textSize = msgBean.fontSize?.toFloat() ?: 24f
val textColor =
templateMessageAdapter.parseColor(msgBean.textColor) ?: Color.WHITE
val dynamicEntity = SVGADynamicEntity()
val textPaint = TextPaint()
textPaint.color = textColor //字體顏色
textPaint.textSize = textSize //字體大小
dynamicEntity.setDynamicText(
StaticLayout(
text,
0,
text.length,
textPaint,
0,
Layout.Alignment.ALIGN_CENTER,
1.0f,
0.0f,
false
), textKey
)
val skipType = msgBean.skipType
if (skipType != null) {
svgaImageView.setOnClickListener {
if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) {
showUserCardAction?.invoke(msgBean.skipContent?:"")
} else {
CommonJumpHelper.bannerJump(context, skipType, msgBean.skipContent)
}
}
}
val drawable = SVGADrawable(videoItem, dynamicEntity)
svgaImageView.setImageDrawable(drawable)
svgaImageView.stepToFrame(0, true)
}
override fun onError() {
endAction.invoke()
}
},
null
)
}
private fun showLuckySeaNotifyBySVGA(roomPlayBean: RoomPlayBean) {
val chatRoomMessage = roomPlayBean.chatRoomMessage
val attachment = chatRoomMessage.attachment as RoomLuckySeaAttachment
@@ -791,6 +1050,90 @@ class RoomEffectView @JvmOverloads constructor(
)
}
private fun showZooNotifyBySVGA(roomPlayBean: RoomPlayBean) {
val chatRoomMessage = roomPlayBean.chatRoomMessage
val attachment = chatRoomMessage.attachment as RoomLuckySeaAttachment
val bean = attachment.roomLuckySeaMsgInfo
val text = SpannableBuilder()
.append(
ResUtil.getString(R.string.congratulation),
ForegroundColorSpan(Color.WHITE)
)
.append(
bean.nick + " ",
ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_FEF23E))
)
.append(
ResUtil.getString(R.string.in_the_zoo),
ForegroundColorSpan(Color.WHITE)
)
.append(
bean.itemMultiple.toString(),
ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF))
)
.append(
ResUtil.getString(R.string.times_reward_get),
ForegroundColorSpan(Color.WHITE)
)
.append(
bean.diamonds.toString(),
ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF))
)
.append(
ResUtil.getString(R.string.diamond_point),
ForegroundColorSpan(Color.WHITE)
)
val svgaImageView = SVGAImageView(mContext)
svgaImageView.loops = 1
svgaImageView.clearsAfterDetached = true
val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
svgaImageView.layoutParams = params
svgaImageView.callback = object : SimpleSvgaCallback() {
override fun onFinished() {
binding.flPlayNotify.post {
playNotifyStateLiveData?.value = false
binding.flPlayNotify.removeView(svgaImageView)
}
}
}
binding.flPlayNotify.addView(svgaImageView)
shareParser().decodeFromAssets(
"svga/zoo_notify.svga",
object : SVGAParser.ParseCompletion {
override fun onComplete(videoItem: SVGAVideoEntity) {
val dynamicEntity = SVGADynamicEntity()
val textPaint = TextPaint()
textPaint.color = Color.WHITE //字體顏色
textPaint.textSize = 24f //字體大小
dynamicEntity.setDynamicText(
StaticLayout(
text.build(),
0,
text.build().length,
textPaint,
0,
Layout.Alignment.ALIGN_CENTER,
1.0f,
0.0f,
false
), "noble_text_tx"
)
svgaImageView.setOnClickListener {
if (!TextUtils.isEmpty(bean.skipUrl)) {
CommonWebViewActivity.start(mContext, bean.skipUrl)
}
}
val drawable = SVGADrawable(videoItem, dynamicEntity)
svgaImageView.setImageDrawable(drawable)
svgaImageView.stepToFrame(0, true)
}
override fun onError() {}
},
null
)
}
private fun showNotifyH5(data: NotifyH5Info) {
val textView = LayoutInflater.from(mContext)
.inflate(R.layout.layout_notify_h5, null) as TextView

View File

@@ -2,6 +2,7 @@ package com.yizhuan.erban.avroom.widget
import android.content.Context
import android.graphics.Color
import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod
import android.text.style.ForegroundColorSpan
import android.view.View
@@ -9,6 +10,7 @@ import android.widget.TextView
import com.chuhai.utils.UiUtils
import com.yizhuan.erban.common.widget.OriginalDrawStatusClickSpan
import com.yizhuan.erban.utils.CommonJumpHelper
import com.yizhuan.erban.utils.SpannableBuilder
import com.yizhuan.xchat_android_core.home.bean.BannerInfo
import com.yizhuan.xchat_android_core.im.custom.bean.TemplateMessage
import com.yizhuan.xchat_android_core.im.custom.bean.TemplateMessage.TemplateNode
@@ -17,7 +19,47 @@ import com.yizhuan.xchat_android_core.im.custom.bean.TemplateMessage.TemplateNod
* Created by Max on 2024/2/22 17:20
* Desc:模版消息适配器
**/
class TemplateMessageAdapter(val listener: Listener) {
class TemplateMessageAdapter(val listener: Listener?) {
/**
* 解析为文本子节点只支持TEXT类型
*/
fun parse(context: Context, attachment: TemplateMessage?): SpannableStringBuilder? {
val builder = SpannableBuilder()
if (attachment == null) {
return null
}
val nodeList = attachment.getNodeList()
nodeList.forEach {
if (it is TemplateNode.NormalNode) {
val textColor = parseColor(it.textColor)
if (textColor != null) {
builder.append(it.text, ForegroundColorSpan(textColor))
} else {
builder.append(it.text)
}
} else if (it is TemplateNode.SpecialNode) {
when (it.content.type) {
TemplateMessage.Content.TEXT -> {
val text = it.content.text?.getFirstText()
if (!text.isNullOrEmpty()) {
val textColor = parseColor(it.content.textColor)
val clickSpan = createClickSpan(context, it.content, listener)
val list = ArrayList<Any>()
if (textColor != null) {
list.add(ForegroundColorSpan(textColor))
}
if (clickSpan != null) {
list.add(clickSpan)
}
builder.append(text, *list.toArray())
}
}
}
}
}
return builder.build()
}
fun convert(textView: TextView, attachment: TemplateMessage?) {
if (attachment == null) {
@@ -40,7 +82,7 @@ class TemplateMessageAdapter(val listener: Listener) {
val text = it.content.text?.getFirstText()
if (!text.isNullOrEmpty()) {
val textColor = parseColor(it.content.textColor)
val clickSpan = createClickSpan(textView.context, it.content)
val clickSpan = createClickSpan(textView.context, it.content, listener)
val list = ArrayList<Any>()
if (textColor != null) {
list.add(ForegroundColorSpan(textColor))
@@ -56,7 +98,7 @@ class TemplateMessageAdapter(val listener: Listener) {
val image = it.content.image
val width = it.content.width ?: 0
val height = it.content.height ?: 0
val clickSpan = createClickSpan(textView.context, it.content)
val clickSpan = createClickSpan(textView.context, it.content, listener)
if (height > 0 && width == 0) {
if (clickSpan != null) {
textBuilder.append(
@@ -99,7 +141,8 @@ class TemplateMessageAdapter(val listener: Listener) {
private fun createClickSpan(
context: Context,
content: TemplateMessage.Content
content: TemplateMessage.Content,
listener: Listener?
): OriginalDrawStatusClickSpan? {
val skipType = content.getSkipType()
val skipUri = content.getSkipUri()
@@ -107,7 +150,7 @@ class TemplateMessageAdapter(val listener: Listener) {
return object : OriginalDrawStatusClickSpan() {
override fun onClick(widget: View) {
if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) {
listener.onShowUserCard(skipUri)
listener?.onShowUserCard(skipUri)
} else {
CommonJumpHelper.bannerJump(context, content)
}
@@ -118,7 +161,10 @@ class TemplateMessageAdapter(val listener: Listener) {
}
}
private fun parseColor(color: String?): Int? {
fun parseColor(color: String?): Int? {
if (color == null) {
return null
}
try {
return Color.parseColor(color)
} catch (e: java.lang.Exception) {

View File

@@ -6,6 +6,8 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MESS_SUB_RENEWNOBLE;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ALL_SERVICE_GIFT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_BOX;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_FAIRY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEADER_TYPE_GIFT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_GIFT;
@@ -17,6 +19,8 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_RED_PACKAGE_RECEIVE_ALL_DIAMOND;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_VIP;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_VIP_USER_ALL_UPGRADE;
import static com.yizhuan.xchat_android_library.utils.UIUtils.getActivityByContext;
@@ -105,6 +109,7 @@ import com.yizhuan.xchat_android_core.im.custom.bean.NotifyH5Info;
import com.yizhuan.xchat_android_core.im.custom.bean.PlayEffectInfo;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomBoxPrizeInfo;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomLuckySeaMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTemplateNotifyMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.TarotMsgBean;
import com.yizhuan.xchat_android_core.manager.AvRoomDataManager;
import com.yizhuan.xchat_android_core.manager.IMNetEaseManager;
@@ -883,6 +888,10 @@ public abstract class BaseActivity extends RxAppCompatActivity
return rxPermissions.request(mPerms);
}
public RxPermissions getRxPermissions(){
return rxPermissions;
}
/**
* 接收到全局广播信息
*
@@ -1099,7 +1108,7 @@ public abstract class BaseActivity extends RxAppCompatActivity
if (roomLuckySeaMsgBean == null) return;
if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL) {
PlayEffectInfo playEffectInfo = new PlayEffectInfo();
playEffectInfo.setSecond(CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL);
playEffectInfo.setSecond(baseProtocol.getSecond());
playEffectInfo.setRoomLuckySeaMsgBean(roomLuckySeaMsgBean);
playEffectList.add(playEffectInfo);
if (playEffectDialog != null && playEffectDialog.isShowing()) {
@@ -1115,6 +1124,64 @@ public abstract class BaseActivity extends RxAppCompatActivity
}
}
break;
case CUSTOM_MSG_CRAZY_ZOO://疯狂动物园
if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return;
if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity
|| this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity
|| UserUtils.getUserInfo() == null)
return;
if (playEffectList == null) {
playEffectList = new LinkedList<>();
}
RoomLuckySeaMsgBean roomLuckySeaMsgBean2 = JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomLuckySeaMsgBean.class);
if (roomLuckySeaMsgBean2 == null) return;
if (baseProtocol.getSecond() == CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM) {
PlayEffectInfo playEffectInfo = new PlayEffectInfo();
playEffectInfo.setSecond(baseProtocol.getSecond());
playEffectInfo.setRoomLuckySeaMsgBean(roomLuckySeaMsgBean2);
playEffectList.add(playEffectInfo);
if (playEffectDialog != null && playEffectDialog.isShowing()) {
// 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个
PlayEffectInfo dataBean = playEffectList.peekFirst();
if (dataBean != null) {
return;
} else {
playEffectDialog.dismiss();
}
} else {
showPlayEffectDialog();
}
}
break;
case CUSTOM_MSG_TEMPLATE_NOTIFY://通用飘屏
if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return;
if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity
|| this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity
|| UserUtils.getUserInfo() == null)
return;
if (playEffectList == null) {
playEffectList = new LinkedList<>();
}
RoomTemplateNotifyMsgBean templateNotifyMsgBean = JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomTemplateNotifyMsgBean.class);
if (templateNotifyMsgBean == null) return;
if (baseProtocol.getSecond() == CUSTOM_MSG_TEMPLATE_NOTIFY_ALL) {
PlayEffectInfo playEffectInfo = new PlayEffectInfo();
playEffectInfo.setSecond(baseProtocol.getSecond());
playEffectInfo.setTemplateNotifyMsgBean(templateNotifyMsgBean);
playEffectList.add(playEffectInfo);
if (playEffectDialog != null && playEffectDialog.isShowing()) {
// 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个
PlayEffectInfo dataBean = playEffectList.peekFirst();
if (dataBean != null) {
return;
} else {
playEffectDialog.dismiss();
}
} else {
showPlayEffectDialog();
}
}
break;
case CUSTOM_MSG_LUCKY_GIFT://福袋
if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return;
if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity

View File

@@ -533,6 +533,42 @@ class HomeFairyActivity : BaseViewBindingActivity<TreasureFairyDialogHomeBinding
.noticeRoomEvent(message, RoomEvent.LUCKY_SEA_GIFT_SERVER_NOTIFY)
}
CustomAttachment.CUSTOM_MSG_CRAZY_ZOO -> if (baseProtocol.second == CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM) {
val attachment = RoomLuckySeaAttachment(
CustomAttachment.CUSTOM_MSG_CRAZY_ZOO,
CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM
)
attachment.setRoomLuckySeaMsgBean(
JSON.parseObject(
baseProtocol.data.toString(),
RoomLuckySeaMsgBean::class.java
)
)
val message = ChatRoomMessageBuilder.createChatRoomCustomMessage(
AvRoomDataManager.get().roomId.toString(),
attachment
)
IMNetEaseManager.get()
.noticeRoomEvent(message, RoomEvent.CRAZY_ZOO_ALL_ROOM_NOTIFY)
}
CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY -> if (baseProtocol.second == CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL) {
val attachment = RoomTemplateNotifyAttachment(
CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY,
CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL
)
attachment.msgBean = JSON.parseObject(
baseProtocol.data.toString(),
RoomTemplateNotifyMsgBean::class.java
)
val message = ChatRoomMessageBuilder.createChatRoomCustomMessage(
AvRoomDataManager.get().roomId.toString(),
attachment
)
IMNetEaseManager.get()
.noticeRoomEvent(message, RoomEvent.TEMPLATE_NOTIFY)
}
CustomAttachment.CUSTOM_MSG_LUCKY_GIFT -> if (baseProtocol.second == CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY || baseProtocol.second == CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) {
val attachment =
RoomReceivedLuckyGiftAttachment(CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY)

View File

@@ -0,0 +1,196 @@
package com.yizhuan.erban.ui.invite
import android.Manifest
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import androidx.core.view.drawToBitmap
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.chuhai.utils.ktx.saveToAlbum
import com.netease.nim.uikit.support.glide.GlideApp
import com.tbruyelle.rxpermissions2.RxPermissions
import com.yizhuan.erban.R
import com.yizhuan.erban.common.widget.dialog.DialogManager
import com.yizhuan.erban.databinding.ShareInviteImageLayoutBinding
import com.yizhuan.erban.ui.widget.magicindicator.buildins.UIUtil
import com.yizhuan.xchat_android_library.utils.SingleToastUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.jvm.Throws
/**
* Created by Max on 2024/3/11 15:57
* Desc:邀请图片
**/
class InviteImageHelper {
fun saveToAlbum(
activity: FragmentActivity,
rxPermissions: RxPermissions,
data: ShareInviteInfo,
success: (() -> Unit)? = null
) {
checkStoragePermissions(rxPermissions) {
if (it) {
saveToAlbumImpl(activity, activity.lifecycleScope, data, success)
} else {
SingleToastUtil.showToast(activity.getString(R.string.ask_again))
}
}
}
private fun checkStoragePermissions(rxPermissions: RxPermissions, call: (Boolean) -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
call.invoke(true)
} else {
val permissions = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
val d = rxPermissions.request(*permissions)?.subscribe({
if (it) {
call.invoke(true)
} else {
call.invoke(false)
}
}, {
it.printStackTrace()
})
}
}
private fun saveToAlbumImpl(
context: Activity,
lifecycleCoroutineScope: LifecycleCoroutineScope,
data: ShareInviteInfo,
success: (() -> Unit)? = null
) {
lifecycleCoroutineScope.launch {
val dialogManager = DialogManager(context)
dialogManager.showProgressDialog(context, false)
try {
val result = saveToAlbum(context, data)
if (result) {
SingleToastUtil.showToast(R.string.community_photo_bigphotoactivity_05)
success?.invoke()
} else {
SingleToastUtil.showToast(R.string.community_photo_bigphotoactivity_06)
}
} catch (e: Exception) {
e.printStackTrace()
SingleToastUtil.showToast(e.message)
} finally {
dialogManager.dismissDialog()
}
}
}
@Throws
suspend fun saveToAlbum(context: Context, data: ShareInviteInfo): Boolean {
val bitmap = generateBitmap(context, data)
return saveToAlbum(context, bitmap)
}
@Throws
suspend fun generateBitmap(context: Context, data: ShareInviteInfo): Bitmap {
val qrcodeUrl = data.qrCodeUrl
if (qrcodeUrl.isNullOrEmpty()) {
throw IllegalArgumentException(context.getString(R.string.utils_net_beanobserver_05))
}
val bitmap: Bitmap
withContext(Dispatchers.IO) {
val qrCode = loadQrcode(context, data.qrCodeUrl)
data.qrcodeDrawable = qrCode
val binding = createView(context)
withContext(Dispatchers.Main) {
bindView(binding, data)
}
bitmap = viewToBitmap(binding.root, UIUtil.dip2px(context, 375.0))
}
return bitmap
}
suspend fun saveToAlbum(context: Context, bitmap: Bitmap): Boolean {
val uri: Uri?
withContext(Dispatchers.IO) {
val fileName = "piko_invite_${System.currentTimeMillis()}.jpg"
uri = bitmap.saveToAlbum(
context = context,
fileName = fileName,
relativePath = null,
quality = 90
)
}
return uri != null
}
private fun bindView(
binding: ShareInviteImageLayoutBinding,
data: ShareInviteInfo
) {
binding.ivQrcode.setImageDrawable(data.qrcodeDrawable)
if (data.text.isNullOrEmpty()) {
binding.tvQrcodeTips.isVisible = false
} else {
binding.tvQrcodeTips.isVisible = true
binding.tvQrcodeTips.text = data.text
}
binding.tvCode.text =
binding.tvCode.context.getString(R.string.invite_code) + data.invitationCode
}
private suspend fun loadQrcode(context: Context, url: String): Drawable? {
return suspendCancellableCoroutine {
val target = GlideApp.with(context.applicationContext).load(url)
.into(object : CustomTarget<Drawable>() {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable>?
) {
it.resume(resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
it.resumeWithException(Exception(context.getString(R.string.utils_net_beanobserver_03)))
}
})
it.invokeOnCancellation {
it?.printStackTrace()
GlideApp.with(context.applicationContext).clear(target)
}
}
}
private fun createView(context: Context): ShareInviteImageLayoutBinding {
return ShareInviteImageLayoutBinding.inflate(LayoutInflater.from(context))
}
private fun viewToBitmap(view: View, width: Int): Bitmap {
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
view.measure(widthMeasureSpec, heightMeasureSpec)
val measureWidth = view.measuredWidth
val measureHeight = view.measuredHeight
view.layout(0, 0, measureWidth, measureHeight)
return view.drawToBitmap()
}
}

View File

@@ -0,0 +1,134 @@
package com.yizhuan.erban.ui.invite
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import cn.sharesdk.facebook.Facebook
import cn.sharesdk.framework.Platform
import cn.sharesdk.framework.PlatformActionListener
import cn.sharesdk.line.Line
import com.chuhai.utils.ktx.singleClick
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.tbruyelle.rxpermissions2.RxPermissions
import com.yizhuan.erban.R
import com.yizhuan.erban.databinding.ShareInviteDialogBinding
import com.yizhuan.xchat_android_library.utils.ResUtil
import com.yizhuan.xchat_android_library.utils.SingleToastUtil
/**
* Created by Max on 2024/3/11 15:29
* Desc:分享邀请
**/
class ShareInviteDialog(val data: ShareInviteInfo) : BottomSheetDialogFragment() {
private var binding: ShareInviteDialogBinding? = null
private var rxPermissions: RxPermissions? = null
private val inviteImageHelper = InviteImageHelper()
override fun onAttach(context: Context) {
super.onAttach(context)
rxPermissions = RxPermissions(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initEvent()
}
private fun initEvent() {
binding?.let { binding ->
binding.tvCancel.singleClick {
dismissAllowingStateLoss()
}
binding.tvSaveToAlbum.singleClick {
rxPermissions?.let {
inviteImageHelper.saveToAlbum(requireActivity(), it, data) {
dismissAllowingStateLoss()
}
}
}
binding.tvShareLink.singleClick {
copyLink(data.toUrl ?: "")
}
binding.tvLine.singleClick {
share(Line(), data)
}
binding.tvFacebook.singleClick {
share(Facebook(), data)
}
}
}
private fun copyLink(data: String) {
try {
val cm =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
cm?.setPrimaryClip(ClipData.newPlainText("text", data))
SingleToastUtil.showToast(R.string.have_copy)
dismissAllowingStateLoss()
} catch (e: Exception) {
e.printStackTrace()
SingleToastUtil.showToast(R.string.avroom_activity_roomblacklistactivity_015)
}
}
private fun share(platform: Platform, data: ShareInviteInfo) {
val url = data.toUrl
val sp = Platform.ShareParams()
sp.imageUrl = data.shareImg
when (platform.name) {
Facebook.NAME -> {
sp.title = data.shareTitle
sp.text = data.shareText
sp.url = url
sp.shareType = Platform.SHARE_WEBPAGE
}
Line.NAME -> {
sp.text = "${data.shareTitle}[$url]"
}
}
platform.platformActionListener = object : PlatformActionListener {
override fun onComplete(platform: Platform, i: Int, hashMap: HashMap<String, Any>) {
SingleToastUtil.showToast(R.string.xchat_android_core_share_sharemodel_01)
dismissAllowingStateLoss()
}
override fun onError(platform: Platform, i: Int, throwable: Throwable) {
val errorMsg: String
if (throwable.message?.contains("not installed") == true) {
errorMsg =
ResUtil.getString(R.string.not_install_app)
} else {
errorMsg =
ResUtil.getString(R.string.xchat_android_core_share_sharemodel_02)
}
SingleToastUtil.showToast(errorMsg)
}
override fun onCancel(platform: Platform, i: Int) {
SingleToastUtil.showToast(R.string.xchat_android_core_share_sharemodel_03)
}
}
platform.share(sp)
}
override fun getTheme(): Int {
return R.style.ErbanBottomSheetDialog
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = ShareInviteDialogBinding.inflate(inflater)
return binding?.root
}
}

View File

@@ -0,0 +1,31 @@
package com.yizhuan.erban.ui.invite
import android.graphics.drawable.Drawable
import androidx.annotation.Keep
import java.io.Serializable
/**
* Created by Max on 2024/3/11 18:56
* Desc:分享邀请相关信息
**/
@Keep
data class ShareInviteInfo(
// 二维码图片
val qrCodeUrl: String? = null,
// 邀请码
val invitationCode: String? = null,
// 页面文案
val text: String? = null,
// 分享文案
val shareText: String? = null,
// 分享图片
val shareImg: String? = null,
// 分享标题
val shareTitle: String? = null,
// 跳转网页地址
val toUrl: String? = null,
// 1分享2保存
val type: Int? = null,
@Transient
var qrcodeDrawable: Drawable? = null
) : Serializable

View File

@@ -16,6 +16,9 @@ import com.yizhuan.erban.base.BaseViewBindingActivity
import com.yizhuan.erban.common.widget.dialog.DialogManager.OkCancelDialogListener
import com.yizhuan.erban.databinding.ActivitySettingBinding
import com.yizhuan.erban.ui.im.avtivity.BlackListManageActivity
import com.yizhuan.erban.ui.invite.InviteImageHelper
import com.yizhuan.erban.ui.invite.ShareInviteDialog
import com.yizhuan.erban.ui.invite.ShareInviteInfo
import com.yizhuan.erban.ui.login.BindPhoneActivity
import com.yizhuan.erban.ui.login.ShowBindPhoneActivity
import com.yizhuan.erban.ui.login.helper.LogoutHelper
@@ -43,7 +46,8 @@ import kotlin.random.Random
* 设置页
* Created by wushaocheng on 2023/2/1.
*/
class SettingActivity : BaseViewBindingActivity<ActivitySettingBinding>(), View.OnClickListener,ILog {
class SettingActivity : BaseViewBindingActivity<ActivitySettingBinding>(), View.OnClickListener,
ILog {
override fun init() {
EventBus.getDefault().register(this)
initWhiteTitleBar(ResUtil.getString(R.string.ui_setting_settingactivity_01))
@@ -217,9 +221,25 @@ class SettingActivity : BaseViewBindingActivity<ActivitySettingBinding>(), View.
}
private fun debug() {
// CommonWebViewActivity.start(
// this,
// "http://192.168.19.136:5502/view/peko/activity/2024-invitationFission/share.html"
// )
val qrcodeUrl =
"https://img0.baidu.com/it/u=4220524728,2310074610&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1710349200&t=39faa005691f3ebde5b8bf2b99708f1b"
val data = ShareInviteInfo(
qrCodeUrl = qrcodeUrl,
invitationCode = Random.nextInt().toString(),
text = "扫码下载PiKO并填写我的邀请码立得1000钻石!!",
shareTitle = "分享标题",
shareText = "分享文本",
shareImg = qrcodeUrl,
toUrl = "https://www.baidu.com",
)
// InviteImageHelper().saveToAlbum(this, rxPermissions, data)
ShareInviteDialog(data).show(supportFragmentManager, "A")
// val json = "{\"data\":{\"diamonds\":225000,\"itemId\":32,\"itemMultiple\":45,\"nick\":\"XG001\",\"roomUid\":2881,\"uid\":2881},\"first\":95,\"second\":955}"
// RedPackageOpenDialog2().show(this)
// val json = "{\"first\":3,\"second\":32,\"data\":{\"recvUserUid\":2735,\"recvUserAvatar\":\"https://img.pekolive.com/default_avatar.png\",\"recvUserNick\":\"66丢丢丢丢丢多多多的hhhh\",\"sendUserNick\":\"11的ass\",\"sendUserAvatar\":\"http://beta.img.pekolive.com/Fk7aur-1RBqKXC-qqBwMTjivZ3lV?imageslim\",\"sendUserUid\":2737,\"giftUrl\":\"http://beta.img.pekolive.com/Fn6h_gPFD5MwA-Ql_kcWqNpKp0JM?imageslim\",\"giftName\":\"幽靈糖果\",\"giftId\":2075,\"giftNum\":${Random.nextInt(1,1000)},\"giftGolds\":33440,\"notifyStaySecond\":5,\"isHomeShow\":true,\"isSkipRoom\":true,\"isFullScreen\":false,\"isSendMsg\":false,\"roomUid\":2737,\"roomErbanNo\":11,\"roomTitle\":\"11的工会\",\"levelNum\":${Random.nextInt(1,4)}}}"
// onReceivedNimBroadcastMessage(json)
// val json = "{\"first\":85,\"second\":855,\"data\":{\"nick\":\"66丢丢丢丢丢多多多的hhhh\",\"preVipName\":\"子爵\",\"floatPic\":\"https://image.hfighting.com/Fq3JtbK2acO3FN-3vWZo8ldtHfse\",\"uid\":2735,\"currVipName\":\"侯爵\",\"erbanNo\":66,\"roomUid\":2734,\"avatar\":\"https://img.pekolive.com/default_avatar.png\",\"currVipLevel\":5}}"
// onReceivedNimBroadcastMessage(json)
// CommonWebViewActivity.start(this,"https://api.anan.chat/anan_vestBag/modules/rank/index.html#/rank")

View File

@@ -16,6 +16,7 @@ import android.webkit.WebView;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.orhanobut.logger.Logger;
import com.yizhuan.erban.UIHelper;
@@ -27,6 +28,9 @@ import com.yizhuan.erban.family.view.activity.FamilyHomeActivity;
import com.yizhuan.erban.public_chat_hall.activity.PublicChatHallHomeActivity;
import com.yizhuan.erban.ui.im.RouterHandler;
import com.yizhuan.erban.ui.im.avtivity.NimP2PMessageActivity;
import com.yizhuan.erban.ui.invite.InviteImageHelper;
import com.yizhuan.erban.ui.invite.ShareInviteDialog;
import com.yizhuan.erban.ui.invite.ShareInviteInfo;
import com.yizhuan.erban.ui.pay.ChargeActivity;
import com.yizhuan.erban.ui.webview.event.H5NotifyClientEvent;
import com.yizhuan.erban.ui.webview.event.ShowNavEvent;
@@ -63,6 +67,7 @@ import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.HashMap;
/**
* <p> html js 与webview 交互接口</p>
* Created by ${user} on 2017/11/6.
@@ -179,6 +184,31 @@ public class JSInterface {
}
}
@JavascriptInterface
public void savePictureShare(String json) {
Logger.e("savePictureShare: " + json);
try {
CommonWebViewActivity activity = mActivity;
if (activity == null) {
return;
}
ShareInviteInfo info = new Gson().fromJson(json,ShareInviteInfo.class);
if (info.getType() != null) {
if (info.getType() == 1) {
activity.runOnUiThread(() -> {
new ShareInviteDialog(info).show(activity.getSupportFragmentManager(), "SHARE_INVITE#JS");
});
} else if (info.getType() == 2) {
activity.runOnUiThread(() -> {
new InviteImageHelper().saveToAlbum(activity, activity.getRxPermissions(), info, null);
});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 调转钱包页
*/

View File

@@ -1,5 +1,6 @@
package com.yizhuan.erban.ui.widget.dialog;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA;
@@ -8,6 +9,7 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Layout;
import android.text.Spanned;
@@ -27,10 +29,14 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.core.text.HtmlCompat;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.netease.nim.uikit.support.glide.GlideApp;
import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGADynamicEntity;
import com.opensource.svgaplayer.SVGAImageView;
@@ -38,10 +44,12 @@ import com.opensource.svgaplayer.SVGAParser;
import com.opensource.svgaplayer.SVGAVideoEntity;
import com.yizhuan.erban.R;
import com.yizhuan.erban.avroom.activity.AVRoomActivity;
import com.yizhuan.erban.avroom.widget.TemplateMessageAdapter;
import com.yizhuan.erban.common.svga.SimpleSvgaCallback;
import com.yizhuan.erban.databinding.DialogAllPlayEffectBinding;
import com.yizhuan.erban.ui.utils.ImageLoadUtilsV2;
import com.yizhuan.erban.ui.webview.CommonWebViewActivity;
import com.yizhuan.erban.utils.CommonJumpHelper;
import com.yizhuan.erban.utils.RegexUtil;
import com.yizhuan.erban.utils.SpannableBuilder;
import com.yizhuan.xchat_android_core.gift.bean.LuckyBagNoticeInfo;
@@ -50,14 +58,17 @@ import com.yizhuan.xchat_android_core.im.custom.bean.NotifyH5Info;
import com.yizhuan.xchat_android_core.im.custom.bean.PlayEffectInfo;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomBoxPrizeInfo;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomLuckySeaMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTemplateNotifyMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.TarotMsgBean;
import com.yizhuan.xchat_android_core.treasurefairy.FairyMsgInfoBean;
import com.yizhuan.xchat_android_library.utils.ResUtil;
import com.yizhuan.xchat_android_library.utils.StringUtils;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
public class AllPlayEffectDialog extends BaseDialog {
@@ -106,6 +117,9 @@ public class AllPlayEffectDialog extends BaseDialog {
case CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL:
showLuckySeaNotifyBySVGA(playEffectInfo.getRoomLuckySeaMsgBean());
break;
case CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM:
showZooNotifyBySVGA(playEffectInfo.getRoomLuckySeaMsgBean());
break;
case CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL:
showLuckyBagNotify(playEffectInfo.getLuckyBagNoticeInfo());
break;
@@ -118,6 +132,9 @@ public class AllPlayEffectDialog extends BaseDialog {
case CustomAttachment.CUSTOM_MSG_NOTIFY_H5_SUB_WHOLE_SERVICE:
showNotifyH5BySvga(playEffectInfo.getNotifyH5());
break;
case CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL:
showTemplateNotify(playEffectInfo.getTemplateNotifyMsgBean());
break;
default:
break;
}
@@ -279,6 +296,91 @@ public class AllPlayEffectDialog extends BaseDialog {
}
}
private void showZooNotifyBySVGA(RoomLuckySeaMsgBean roomLuckySeaMsgBean) {
SpannableBuilder text = new SpannableBuilder()
.append(
ResUtil.getString(R.string.congratulation),
new ForegroundColorSpan(Color.WHITE)
)
.append(
roomLuckySeaMsgBean.getNick() + " ",
new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_FEF23E))
)
.append(
ResUtil.getString(R.string.in_the_zoo),
new ForegroundColorSpan(Color.WHITE)
)
.append(
String.valueOf(roomLuckySeaMsgBean.getItemMultiple()),
new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_00EAFF))
)
.append(
ResUtil.getString(R.string.times_reward_get),
new ForegroundColorSpan(Color.WHITE)
)
.append(
String.valueOf(roomLuckySeaMsgBean.getDiamonds()),
new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_00EAFF))
)
.append(
ResUtil.getString(R.string.diamond_point),
new ForegroundColorSpan(Color.WHITE)
);
SVGAImageView svgaImageView = new SVGAImageView(getContext());
svgaImageView.setLoops(1);
svgaImageView.setClearsAfterDetached(true);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
svgaImageView.setLayoutParams(params);
svgaImageView.setCallback(new SimpleSvgaCallback() {
@Override
public void onFinished() {
closeSelf();
}
});
binding.flSvgaNotify.addView(svgaImageView);
try {
SVGAParser.Companion.shareParser().decodeFromAssets("svga/zoo_notify.svga", new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) {
SVGADynamicEntity dynamicEntity = new SVGADynamicEntity();
TextPaint textPaint = new TextPaint();
textPaint.setColor(Color.WHITE);//字体颜色
textPaint.setTextSize(24);//字体大小
dynamicEntity.setDynamicText(new StaticLayout(
text.build(),
0,
text.build().length(),
textPaint,
0,
Layout.Alignment.ALIGN_CENTER,
1.0f,
0.0f,
false
), "noble_text_tx");
svgaImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!TextUtils.isEmpty(roomLuckySeaMsgBean.getSkipUrl())) {
CommonWebViewActivity.start(getContext(), roomLuckySeaMsgBean.getSkipUrl());
}
}
});
SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity);
svgaImageView.setImageDrawable(drawable);
svgaImageView.stepToFrame(0, true);
}
@Override
public void onError() {
closeSelf();
}
}, null);
} catch (Exception e) {
e.printStackTrace();
closeSelf();
}
}
private void showLuckyBagNotify(LuckyBagNoticeInfo noticeInfo) {
View roomView = LayoutInflater.from(getContext())
.inflate(R.layout.layout_room_lucky_bag_notify, null);
@@ -332,11 +434,11 @@ public class AllPlayEffectDialog extends BaseDialog {
binding.flSvgaNotify.addView(roomView,params);
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_box_notify);
roomView.startAnimation(animation);
disposable.add(Observable.timer(6500, TimeUnit.MILLISECONDS).subscribe(aLong -> {
disposable.add(Observable.timer(6500, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> {
Animation animation1 = AnimationUtils.loadAnimation(getContext(), R.anim.anim_box_notify_close);
roomView.startAnimation(animation1);
}));
disposable.add(Observable.timer(7000, TimeUnit.MILLISECONDS).subscribe(aLong -> closeSelf()));
disposable.add(Observable.timer(7000, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> closeSelf()));
}
private void showNotifyH5BySvga(NotifyH5Info info) {
@@ -499,6 +601,181 @@ public class AllPlayEffectDialog extends BaseDialog {
}
}
private void showTemplateNotify(RoomTemplateNotifyMsgBean msgBean) {
if (msgBean == null) {
closeSelf();
return;
}
String resourceType = msgBean.getResourceType();
if (resourceType == null) {
closeSelf();
return;
}
if (resourceType.equals("IMAGE")) {
showTemplateImageNotify(msgBean);
} else if (resourceType.equals("SVGA")) {
showTemplateSvgaNotify(msgBean);
}
}
private void showTemplateImageNotify(@NonNull RoomTemplateNotifyMsgBean msgBean) {
if (msgBean.getResourceType() == null || !msgBean.getResourceType().equals("IMAGE")) {
closeSelf();
return;
}
String resourceContent = msgBean.getResourceContent();
if (resourceContent == null || resourceContent.isEmpty()) {
closeSelf();
return;
}
Runnable endAction = new Runnable() {
@Override
public void run() {
closeSelf();
}
};
View rootView = LayoutInflater.from(getContext())
.inflate(R.layout.layout_room_template_notify_image, null);
TemplateMessageAdapter adapter = new TemplateMessageAdapter(null);
TextView textView = rootView.findViewById(R.id.tv_text);
Integer textSize = msgBean.getFontSize();
if (textSize == null) {
textSize = 12;
}
textView.setTextSize(textSize);
Integer textColor = adapter.parseColor(msgBean.getTextColor());
if (textColor == null) {
textColor = Color.WHITE;
}
textView.setTextColor(textColor);
ImageView bgView = rootView.findViewById(R.id.iv_bg);
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
binding.flTemplateNotify.addView(rootView, params);
GlideApp.with(bgView)
.load(resourceContent).into(new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
adapter.convert(textView, msgBean);
bgView.setImageDrawable(resource);
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_box_notify);
rootView.startAnimation(animation);
View.OnClickListener clickAction = v -> {
Integer skipType = msgBean.getSkipType();
if (skipType == null) {
return;
}
CommonJumpHelper.bannerJump(getContext(), skipType, msgBean.getSkipContent());
};
rootView.setOnClickListener(clickAction);
textView.setOnClickListener(clickAction);
disposable.add(Observable.timer(6500, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> {
Animation animation1 = AnimationUtils.loadAnimation(getContext(), R.anim.anim_box_notify_close);
rootView.startAnimation(animation1);
}));
disposable.add(Observable.timer(7000, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> endAction.run()));
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
endAction.run();
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
endAction.run();
}
});
}
private void showTemplateSvgaNotify(@NonNull RoomTemplateNotifyMsgBean msgBean) {
if (msgBean.getResourceType() == null || !msgBean.getResourceType().equals("SVGA")) {
closeSelf();
return;
}
String resourceContent = msgBean.getResourceContent();
if (resourceContent == null || resourceContent.isEmpty()) {
closeSelf();
return;
}
Runnable endAction = new Runnable() {
@Override
public void run() {
closeSelf();
}
};
SVGAImageView svgaImageView = new SVGAImageView(getContext());
svgaImageView.setLoops(1);
svgaImageView.setClearsAfterDetached(true);
svgaImageView.setCallback(new SimpleSvgaCallback() {
@Override
public void onFinished() {
endAction.run();
}
});
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, 0);
params.dimensionRatio = msgBean.getDimensionRatio();
if (params.dimensionRatio == null) {
params.dimensionRatio = "75:11";
}
binding.flTemplateNotify.addView(svgaImageView, params);
try {
SVGAParser.Companion.shareParser().decodeFromURL(new URL(resourceContent), new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) {
TemplateMessageAdapter adapter = new TemplateMessageAdapter(null);
CharSequence text = adapter.parse(getContext(), msgBean);
if (text == null) {
text = "";
}
String textKey = msgBean.getSvgaTextKey();
int textSize = 24;
if (msgBean.getFontSize() != null) {
textSize = msgBean.getFontSize();
}
int textColor = Color.WHITE;
Integer color = adapter.parseColor(msgBean.getTextColor());
if (color != null) {
textColor = color;
}
SVGADynamicEntity dynamicEntity = new SVGADynamicEntity();
TextPaint textPaint = new TextPaint();
textPaint.setColor(textColor);//字体颜色
textPaint.setTextSize(textSize);//字体大小
dynamicEntity.setDynamicText(new StaticLayout(
text,
0,
text.length(),
textPaint,
0,
Layout.Alignment.ALIGN_CENTER,
1.0f,
0.0f,
false
), textKey);
svgaImageView.setOnClickListener(v -> {
Integer skipType = msgBean.getSkipType();
if (skipType == null) {
return;
}
CommonJumpHelper.bannerJump(getContext(), skipType, msgBean.getSkipContent());
});
SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity);
svgaImageView.setImageDrawable(drawable);
svgaImageView.stepToFrame(0, true);
}
@Override
public void onError() {
endAction.run();
}
}, null);
} catch (Exception e) {
e.printStackTrace();
endAction.run();
}
}
private String subAndReplaceDot(String nick, int maxLength) {
if (nick.length() > maxLength) {
return nick.substring(0, maxLength) + "...";

View File

@@ -29,37 +29,47 @@ public class CommonJumpHelper {
* @param context
*/
public static void bannerJump(Context context, IRouterData bannerInfo) {
int skipType = bannerInfo.getSkipType();
if (skipType == SKIP_TYPE_ROUTER) {
bannerJump(context, JavaUtil.str2int(bannerInfo.getRouterType()), bannerInfo.getRouterValue());
} else {
bannerJump(context, skipType, bannerInfo.getSkipUri());
}
}
if (null == context || null == bannerInfo) {
/**
* 通用跳转
*
* @param context
*/
public static void bannerJump(Context context, int skipType, String skipContent) {
if (null == context) {
return;
}
int skipType = bannerInfo.getSkipType();
String url = bannerInfo.getSkipUri();
switch (skipType) {
case SKIP_TYP_APP:
if (TextUtils.isEmpty(url)) {
if (TextUtils.isEmpty(skipContent)) {
return;
}
RouterHandler.handle(context, JavaUtil.str2int(url), null);
RouterHandler.handle(context, JavaUtil.str2int(skipContent), null);
break;
case SKIP_TYP_CHAT_ROOM:
if (TextUtils.isEmpty(url)) {
if (TextUtils.isEmpty(skipContent)) {
return;
}
AVRoomActivity.start(context, JavaUtil.str2long(url));
AVRoomActivity.start(context, JavaUtil.str2long(skipContent));
break;
case SKIP_TYP_H5:
if (TextUtils.isEmpty(url)) {
if (TextUtils.isEmpty(skipContent)) {
return;
}
Intent intent = new Intent(context, CommonWebViewActivity.class);
intent.putExtra("url", url);
intent.putExtra("url", skipContent);
context.startActivity(intent);
break;
case SKIP_TYPE_ROUTER:
RouterHandler.handle(context, JavaUtil.str2int(bannerInfo.getRouterType()), bannerInfo.getRouterValue());
RouterHandler.handle(context, skipType, skipContent);
break;
default:
break;

View File

@@ -42,6 +42,27 @@ public class SpannableBuilder {
return this;
}
/**
* 支持多個spannable 對同一段文字修改
*
* @param text
* @param what
* @return
*/
public SpannableBuilder append(CharSequence text, Object... what) {
if (TextUtils.isEmpty(text)) return this;
int start = builder.length();
builder.append(text);
for (int i = 0; i < what.length; i++) {
Object o = what[i];
if (o == null) {
continue;
}
builder.setSpan(what[i], start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
return this;
}
public SpannableStringBuilder build() {
return builder;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -26,4 +26,10 @@
app:layout_constraintTop_toBottomOf="@id/v_gift_notify_placeholder"
app:layout_goneMarginTop="0dp" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fl_template_notify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/fl_svga_notify" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -52,6 +52,12 @@
app:layout_constraintDimensionRatio="75:11"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fl_template_notify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/fl_lucky_bag_notify"
android:layout_width="match_parent"

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_bg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/bg_zoo_notice" />
<com.coorchice.library.SuperTextView
android:id="@+id/tv_text"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="false"
android:lineSpacingExtra="0dp"
android:lineSpacingMultiplier="0.8"
android:maxLines="2"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/iv_bg"
app:layout_constraintEnd_toEndOf="@id/iv_bg"
app:layout_constraintStart_toStartOf="@id/iv_bg"
app:layout_constraintTop_toTopOf="@id/iv_bg"
app:layout_constraintWidth_percent="0.626"
tools:layout_height="wrap_content"
tools:text="@string/layout_layout_room_box_notify_01" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<com.coorchice.library.SuperTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="@drawable/bg_zoo_notice"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="false"
android:lineSpacingExtra="0dp"
android:lineSpacingMultiplier="0.8"
android:maxLines="2"
android:paddingStart="80dp"
android:paddingTop="@dimen/dp_6"
android:paddingEnd="80dp"
android:textSize="12sp"
tools:layout_height="wrap_content"
tools:text="@string/layout_layout_room_box_notify_01" />

View File

@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_dialog_share"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dp_15"
android:text="@string/share_to_friends"
android:textColor="@color/color_333333"
android:textSize="@dimen/sp_14" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:layout_marginBottom="@dimen/dp_10"
android:gravity="center"
android:text="@string/title_share_dialog"
android:textColor="@color/color_999999"
android:textSize="13sp"
android:visibility="gone"
tools:ignore="SpUsage" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:gravity="center"
android:orientation="horizontal"
android:weightSum="4">
<TextView
android:id="@+id/tv_line"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_17"
android:layout_marginBottom="19dp"
android:layout_weight="1"
android:drawablePadding="9dp"
android:gravity="center"
android:text="@string/share_line"
android:textColor="@color/color_999999"
android:textSize="@dimen/font_medium"
app:drawableTopCompat="@drawable/icon_line" />
<TextView
android:id="@+id/tv_facebook"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_17"
android:layout_marginBottom="19dp"
android:layout_weight="1"
android:drawablePadding="9dp"
android:gravity="center"
android:text="@string/share_facebook"
android:textColor="@color/color_999999"
android:textSize="@dimen/font_medium"
app:drawableTopCompat="@drawable/icon_facebook" />
<TextView
android:id="@+id/tv_share_link"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_17"
android:layout_marginBottom="19dp"
android:layout_weight="1"
android:drawablePadding="9dp"
android:gravity="center"
android:text="@string/share_link"
android:textColor="@color/color_999999"
android:textSize="@dimen/font_medium"
app:drawableTopCompat="@drawable/ic_share_link" />
<TextView
android:id="@+id/tv_save_to_album"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_17"
android:layout_marginBottom="19dp"
android:layout_weight="1"
android:drawablePadding="9dp"
android:gravity="center"
android:text="@string/save_invite_image"
android:textColor="@color/color_999999"
android:textSize="@dimen/font_medium"
app:drawableTopCompat="@drawable/ic_share_save_to_album" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/tv_cancel"
android:layout_width="match_parent"
android:layout_height="@dimen/common_item_view_height_big"
android:layout_gravity="center"
android:background="@color/color_F5F5F5"
android:gravity="center"
android:text="@string/cancel"
android:textColor="@color/color_999999"
android:textSize="@dimen/sp_14"
tools:ignore="SpUsage" />
</LinearLayout>

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout_marginHorizontal="40dp">
<ImageView
android:id="@+id/iv_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@drawable/share_invite_bg"
app:layout_constraintDimensionRatio="375:812"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/line_title_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.162" />
<ImageView
android:id="@+id/iv_title"
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@drawable/share_invite_ic_text"
app:layout_constraintDimensionRatio="297:32.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/line_title_top"
app:layout_constraintWidth_percent="0.792" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/line_qrcode_bg_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.432" />
<ImageView
android:id="@+id/iv_qrcode_bg"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/shape_white_20dp_round"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.53"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/line_qrcode_bg_top"
app:layout_constraintWidth_percent="0.92" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/line_qrcode_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.55" />
<ImageView
android:id="@+id/iv_qrcode"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/line_qrcode_top"
app:layout_constraintWidth_percent="0.533"
tools:src="@mipmap/app_logo" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/line_code_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.869" />
<TextView
android:id="@+id/tv_code"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/share_invite_bg_code"
android:gravity="center"
android:textColor="@color/color_FFFFFF"
android:textSize="@dimen/dp_16"
app:layout_constraintDimensionRatio="241:46"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/line_code_top"
app:layout_constraintWidth_percent="0.642"
tools:text="邀请码ABCD" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/line_code_tips_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.827" />
<TextView
android:id="@+id/tv_code_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/invite_code_tips"
android:textColor="#999999"
android:textSize="@dimen/dp_10"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/line_code_tips_top" />
<TextView
android:id="@+id/tv_qrcode_tips"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/share_invite_bg_qrcode_tips"
android:gravity="center"
android:includeFontPadding="false"
android:paddingHorizontal="@dimen/dp_20"
android:textColor="@color/color_white"
android:textSize="@dimen/dp_12"
app:layout_constraintDimensionRatio="290:43"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/line_qrcode_bg_top"
app:layout_constraintWidth_percent="0.773"
tools:text="扫码下载PiKO并填写我的邀请码立得1000钻石!!" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -713,5 +713,6 @@
<color name="color_ffffff_30">#4CFFFFFF</color>
<color name="color_FFE468">#FFFFE468</color>
<color name="color_C9CBD1">#C9CBD1</color>
<color name="color_FEF23E">#FEF23E</color>
</resources>

View File

@@ -541,6 +541,7 @@
<string name="tab_title_fans">粉絲</string>
<string name="title_share_dialog">每天第一次分享免費領紅包不包含分享至Piko好友</string>
<string name="text_share_erban_friends">好友</string>
<string name="save_invite_image">保存邀請圖片</string>
<string name="text_share_Google">Google</string>
<string name="tab_title_team"></string>
<string name="text_team_join_auth_on">開啟身份驗證</string>
@@ -4985,6 +4986,7 @@
<string name="room">房間</string>
<string name="congratulation">恭喜</string>
<string name="in_the_star_kitchen_draw">在星級厨房抽中</string>
<string name="in_the_zoo">在瘋狂動物園中</string>
<string name="guardian_planet_msg_1">在守護星球中成功擊敗怪獸,獲得</string>
<string name="guardian_planet_msg_2">鉆石獎勵!</string>
<string name="times_reward_get">倍獎勵,獲得</string>
@@ -5198,4 +5200,6 @@
<string name="all_service_gift_room_go_ignore">下次不再出現此提示</string>
<string name="all_service_gift_room_go_cancel">留在這</string>
<string name="all_service_gift_room_go_go">立即前往</string>
<string name="invite_code">邀請碼:</string>
<string name="invite_code_tips">記得註冊時填寫邀請碼哦~</string>
</resources>

View File

@@ -1,6 +1,8 @@
package com.yizhuan.erban.treasure_box.activity;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_BOX;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_FAIRY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_GIFT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL;
@@ -9,6 +11,8 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -59,6 +63,8 @@ import com.yizhuan.xchat_android_core.im.custom.bean.RoomBoxPrizeInfo;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomLuckySeaAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomLuckySeaMsgBean;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomReceivedLuckyGiftAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTemplateNotifyAttachment;
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTemplateNotifyMsgBean;
import com.yizhuan.xchat_android_core.manager.AvRoomDataManager;
import com.yizhuan.xchat_android_core.manager.IMNetEaseManager;
import com.yizhuan.xchat_android_core.manager.RoomEvent;
@@ -496,6 +502,22 @@ public class TreasureBoxActivity extends BaseBindingActivity<ActivityTreasureBox
IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.LUCKY_SEA_GIFT_SERVER_NOTIFY);
}
break;
case CUSTOM_MSG_CRAZY_ZOO://疯狂动物园
if (baseProtocol.getSecond() == CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM) {
RoomLuckySeaAttachment attachment = new RoomLuckySeaAttachment(CUSTOM_MSG_CRAZY_ZOO, CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM);
attachment.setRoomLuckySeaMsgBean(JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomLuckySeaMsgBean.class));
ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment);
IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.CRAZY_ZOO_ALL_ROOM_NOTIFY);
}
break;
case CUSTOM_MSG_TEMPLATE_NOTIFY://通用飘屏
if (baseProtocol.getSecond() == CUSTOM_MSG_TEMPLATE_NOTIFY_ALL) {
RoomTemplateNotifyAttachment attachment = new RoomTemplateNotifyAttachment(CUSTOM_MSG_TEMPLATE_NOTIFY, CUSTOM_MSG_TEMPLATE_NOTIFY_ALL);
attachment.setMsgBean(JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomTemplateNotifyMsgBean.class));
ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment);
IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.TEMPLATE_NOTIFY);
}
break;
case CUSTOM_MSG_LUCKY_GIFT://福袋
if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY || baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) {
RoomReceivedLuckyGiftAttachment attachment = new RoomReceivedLuckyGiftAttachment(CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY);

View File

@@ -1302,6 +1302,14 @@ public final class IMNetEaseManager {
noticeRoomEvent(msg, RoomEvent.ROOM_PK_ACCEPT);
if (second == CUSTOM_MSG_SUB_SINGLE_ROOM_PK_ACCEPT &&
AuthModel.get().getCurrentUid() == roomPkBean.getInviteUid()) {
/*
* TODO #特殊问题记录#
* 2024.3.12发现问题A给B发出PK邀请B接收后A无法听到B的声音B能听到A的声音
* 问题原因B接收后服务端会发839给AA就连接B了但没有地方触发B连接A
* 临时解决借用839通道、服务端也发839给B但由于线上版本839处理时判断了inviteUid==当前房间(即:上面的判断)
* 所以补发的这条消息某些字段是反的inviteUid、aRoomId、aUid
* 所以后面再处理839事件时需要考虑这点
*/
AudioEngineManager.get().connectOtherRoom(String.valueOf(roomPkBean.getARoomId()), roomPkBean.getAUid());
}
break;
@@ -1463,6 +1471,16 @@ public final class IMNetEaseManager {
case CUSTOM_MSG_ROOM_ALBUM:
addMessages(msg);
break;
case CUSTOM_MSG_CRAZY_ZOO:
if (second == CUSTOM_MSG_CRAZY_ZOO_SUB_ROOM) {
noticeRoomEvent(msg, RoomEvent.CRAZY_ZOO_ROOM_NOTIFY);
}
break;
case CUSTOM_MSG_TEMPLATE_NOTIFY:
if (second == CUSTOM_MSG_TEMPLATE_NOTIFY_ROOM) {
noticeRoomEvent(msg, RoomEvent.TEMPLATE_NOTIFY);
}
break;
default:
break;
}

View File

@@ -14,6 +14,9 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CHATTER_BOX_DROP;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CHATTER_BOX_INIT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CLAN;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_CRAZY_ZOO_SUB_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_DRAGON_BAR;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_DRAW_GIFT_EFFECT;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_EXPER_LEVEL_UP;
@@ -74,6 +77,9 @@ import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUS
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_LUCKY_MONEY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_MULTI_MAGIC;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_SINGLE_MAGIC;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ROOM;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_AUDIO;
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_CLEAN_SCREEN;
@@ -665,6 +671,22 @@ public class CustomAttachParser implements MsgAttachmentParser {
attachment = new TemplateMessageAttachment(first, second);
}
break;
case CUSTOM_MSG_CRAZY_ZOO:
switch (second) {
case CUSTOM_MSG_CRAZY_ZOO_SUB_ROOM:
case CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM:
attachment = new RoomLuckySeaAttachment(first, second);
break;
}
break;
case CUSTOM_MSG_TEMPLATE_NOTIFY:
switch (second) {
case CUSTOM_MSG_TEMPLATE_NOTIFY_ROOM:
case CUSTOM_MSG_TEMPLATE_NOTIFY_ALL:
attachment = new RoomTemplateNotifyAttachment(first, second);
break;
}
break;
default:
LogUtils.e(ResUtil.getString(R.string.custom_bean_customattachparser_01) + first + " second=" + second);
break;

View File

@@ -490,6 +490,17 @@ public class CustomAttachment implements MsgAttachment {
public static final int CUSTOM_MSG_ROOM_TEMPLATE_SUB_ROOM = 1031;
public static final int CUSTOM_MSG_ROOM_TEMPLATE_SUB_ALL_ROOM = 1032;
// 疯狂动物圆
public static final int CUSTOM_MSG_CRAZY_ZOO = 104;
public static final int CUSTOM_MSG_CRAZY_ZOO_SUB_ROOM = 1041;// 动物园房间飘屏通知
public static final int CUSTOM_MSG_CRAZY_ZOO_SUB_ALL_ROOM = 1042;// 动物园全服飘屏通知
// 通用模版飘屏
public static final int CUSTOM_MSG_TEMPLATE_NOTIFY = 105;
public static final int CUSTOM_MSG_TEMPLATE_NOTIFY_ROOM = 1051;// 通用模版飘屏-房间
public static final int CUSTOM_MSG_TEMPLATE_NOTIFY_ALL = 1052;// 通用模版飘屏-全服
/**
* 自定义消息附件的类型,根据该字段区分不同的自定义消息
*/

View File

@@ -17,4 +17,5 @@ public class PlayEffectInfo {
private TarotMsgBean tarotMsgBean;
private NotifyH5Info notifyH5;
private RoomTemplateNotifyMsgBean templateNotifyMsgBean;
}

View File

@@ -0,0 +1,35 @@
package com.yizhuan.xchat_android_core.im.custom.bean
import com.alibaba.fastjson.JSONObject
import com.google.gson.Gson
/**
* Created by Max on 2024/3/18 10:14
* Desc:通用模版飘窗
**/
class RoomTemplateNotifyAttachment : CustomAttachment {
var msgBean: RoomTemplateNotifyMsgBean? = null
constructor() : super()
constructor(first: Int, second: Int) : super(first, second)
public override fun parseData(data: JSONObject?) {
super.parseData(data)
try {
msgBean = Gson().fromJson<RoomTemplateNotifyMsgBean>(
data!!.toJSONString(),
RoomTemplateNotifyMsgBean::class.java
)
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun packData(): JSONObject? {
val jsonStr = Gson().toJson(msgBean)
return JSONObject.parseObject(jsonStr)
}
fun getTemplateMsg() = msgBean
}

View File

@@ -0,0 +1,31 @@
package com.yizhuan.xchat_android_core.im.custom.bean
/**
* Created by Max on 2024/3/15 18:55
* Desc:通用模版飘窗
**/
class RoomTemplateNotifyMsgBean : TemplateMessage() {
var fontSize: Int? = null
// IMAGE、SVGA
var resourceType: String? = null
var resourceContent: String? = null
var skipType: Int? = null
var skipContent: String? = null
var resourceWidth: Int? = null
var resourceHeight: Int? = null
// SVGA-文本的坑位KEY
private var svgaTextKey: String? = null
fun getSvgaTextKey(): String {
return svgaTextKey ?: "noble_text_tx"
}
fun getDimensionRatio(): String? {
if (resourceWidth != null && resourceHeight != null) {
return "$resourceWidth:$resourceHeight"
}
return null
}
}

View File

@@ -10,11 +10,11 @@ import java.util.regex.Pattern
* Created by Max on 2024/2/22 18:51
* Desc:
**/
data class TemplateMessage(
var template: I18N? = null,
var textColor: String? = null,
val contents: List<Content>? = null
) : Serializable {
open class TemplateMessage : Serializable {
var template: I18N? = null
var textColor: String? = null
var contents: List<Content>? = null
private val nodeList: List<TemplateNode>? = null

View File

@@ -264,6 +264,14 @@ public class RoomEvent {
public static final int NOTIFY_H5 = 109;
//疯狂动物园 - 房间飘窗通知
public static final int CRAZY_ZOO_ROOM_NOTIFY = 110;
//疯狂动物园 - 全服房间飘窗通知
public static final int CRAZY_ZOO_ALL_ROOM_NOTIFY = 111;
//通用模版飘屏
public static final int TEMPLATE_NOTIFY = 112;
private int event = NONE;
private int micPosition = Integer.MIN_VALUE;
private int posState = -1;

View File

@@ -31,8 +31,8 @@ COMPILE_SDK_VERSION=33
MIN_SDK_VERSION=21
TARGET_SDK_VERSION=33
version_name=2.6.1
version_code=2601
version_name=2.6.4
version_code=2604
#systemProp.https.proxyHost=127.0.0.1
#systemProp.https.proxyPort=7890

View File

@@ -0,0 +1,253 @@
@file:JvmName("ImageExt")
@file:Suppress("unused")
package com.chuhai.utils.ktx
import android.content.*
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import java.io.File
import java.io.FileNotFoundException
import java.io.InputStream
import java.io.OutputStream
private const val TAG = "ImageToAlbumKtx"
private val ALBUM_DIR = Environment.DIRECTORY_PICTURES
private class OutputFileTaker(var file: File? = null)
/**
* 复制图片文件到相册的Pictures文件夹
*
* @param context 上下文
* @param fileName 文件名。 需要携带后缀
* @param relativePath 相对于Pictures的路径
*/
fun File.copyToAlbum(context: Context, fileName: String, relativePath: String?): Uri? {
if (!this.canRead() || !this.exists()) {
Log.w(TAG, "check: read file error: $this")
return null
}
return this.inputStream().use {
it.saveToAlbum(context, fileName, relativePath)
}
}
/**
* 保存图片Stream到相册的Pictures文件夹
*
* @param context 上下文
* @param fileName 文件名。 需要携带后缀
* @param relativePath 相对于Pictures的路径
*/
fun InputStream.saveToAlbum(context: Context, fileName: String, relativePath: String?): Uri? {
val resolver = context.contentResolver
val outputFile = OutputFileTaker()
val imageUri = resolver.insertMediaImage(fileName, relativePath, outputFile)
if (imageUri == null) {
Log.w(TAG, "insert: error: uri == null")
return null
}
(imageUri.outputStream(resolver) ?: return null).use { output ->
this.use { input ->
input.copyTo(output)
imageUri.finishPending(context, resolver, outputFile.file)
}
}
return imageUri
}
/**
* 保存Bitmap到相册的Pictures文件夹
*
* https://developer.android.google.cn/training/data-storage/shared/media
*
* @param context 上下文
* @param fileName 文件名。 需要携带后缀
* @param relativePath 相对于Pictures的路径
* @param quality 质量
*/
fun Bitmap.saveToAlbum(
context: Context,
fileName: String,
relativePath: String? = null,
quality: Int = 75,
): Uri? {
// 插入图片信息
val resolver = context.contentResolver
val outputFile = OutputFileTaker()
val imageUri = resolver.insertMediaImage(fileName, relativePath, outputFile)
if (imageUri == null) {
Log.w(TAG, "insert: error: uri == null")
return null
}
// 保存图片
(imageUri.outputStream(resolver) ?: return null).use {
val format = fileName.getBitmapFormat()
this@saveToAlbum.compress(format, quality, it)
imageUri.finishPending(context, resolver, outputFile.file)
}
return imageUri
}
private fun Uri.outputStream(resolver: ContentResolver): OutputStream? {
return try {
resolver.openOutputStream(this)
} catch (e: FileNotFoundException) {
Log.e(TAG, "save: open stream error: $e")
null
}
}
private fun Uri.finishPending(
context: Context,
resolver: ContentResolver,
outputFile: File?,
) {
val imageValues = ContentValues()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (outputFile != null) {
imageValues.put(MediaStore.Images.Media.SIZE, outputFile.length())
}
resolver.update(this, imageValues, null, null)
// 通知媒体库更新
val intent = Intent(@Suppress("DEPRECATION") Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, this)
context.sendBroadcast(intent)
} else {
// Android Q添加了IS_PENDING状态为0时其他应用才可见
imageValues.put(MediaStore.Images.Media.IS_PENDING, 0)
resolver.update(this, imageValues, null, null)
}
}
private fun String.getBitmapFormat(): Bitmap.CompressFormat {
val fileName = this.lowercase()
return when {
fileName.endsWith(".png") -> Bitmap.CompressFormat.PNG
fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") -> Bitmap.CompressFormat.JPEG
fileName.endsWith(".webp") -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
Bitmap.CompressFormat.WEBP_LOSSLESS else Bitmap.CompressFormat.WEBP
else -> Bitmap.CompressFormat.PNG
}
}
private fun String.getMimeType(): String? {
val fileName = this.lowercase()
return when {
fileName.endsWith(".png") -> "image/png"
fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") -> "image/jpeg"
fileName.endsWith(".webp") -> "image/webp"
fileName.endsWith(".gif") -> "image/gif"
else -> null
}
}
/**
* 插入图片到媒体库
*/
private fun ContentResolver.insertMediaImage(
fileName: String,
relativePath: String?,
outputFileTaker: OutputFileTaker? = null,
): Uri? {
// 图片信息
val imageValues = ContentValues().apply {
val mimeType = fileName.getMimeType()
if (mimeType != null) {
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
}
val date = System.currentTimeMillis() / 1000
put(MediaStore.Images.Media.DATE_ADDED, date)
put(MediaStore.Images.Media.DATE_MODIFIED, date)
}
// 保存的位置
val collection: Uri
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val path = if (relativePath != null) "${ALBUM_DIR}/${relativePath}" else ALBUM_DIR
imageValues.apply {
put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
put(MediaStore.Images.Media.RELATIVE_PATH, path)
put(MediaStore.Images.Media.IS_PENDING, 1)
}
collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
// 高版本不用查重直接插入,会自动重命名
} else {
// 老版本
val pictures =
@Suppress("DEPRECATION") Environment.getExternalStoragePublicDirectory(ALBUM_DIR)
val saveDir = if (relativePath != null) File(pictures, relativePath) else pictures
if (!saveDir.exists() && !saveDir.mkdirs()) {
Log.e(TAG, "save: error: can't create Pictures directory")
return null
}
// 文件路径查重,重复的话在文件名后拼接数字
var imageFile = File(saveDir, fileName)
val fileNameWithoutExtension = imageFile.nameWithoutExtension
val fileExtension = imageFile.extension
var queryUri = this.queryMediaImage28(imageFile.absolutePath)
var suffix = 1
while (queryUri != null) {
val newName = fileNameWithoutExtension + "(${suffix++})." + fileExtension
imageFile = File(saveDir, newName)
queryUri = this.queryMediaImage28(imageFile.absolutePath)
}
imageValues.apply {
put(MediaStore.Images.Media.DISPLAY_NAME, imageFile.name)
// 保存路径
val imagePath = imageFile.absolutePath
Log.v(TAG, "save file: $imagePath")
put(@Suppress("DEPRECATION") MediaStore.Images.Media.DATA, imagePath)
}
outputFileTaker?.file = imageFile// 回传文件路径,用于设置文件大小
collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
// 插入图片信息
return this.insert(collection, imageValues)
}
/**
* Android Q以下版本查询媒体库中当前路径是否存在
* @return Uri 返回null时说明不存在可以进行图片插入逻辑
*/
private fun ContentResolver.queryMediaImage28(imagePath: String): Uri? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return null
val imageFile = File(imagePath)
if (imageFile.canRead() && imageFile.exists()) {
Log.v(TAG, "query: path: $imagePath exists")
// 文件已存在返回一个file://xxx的uri
return Uri.fromFile(imageFile)
}
// 保存的位置
val collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
// 查询是否已经存在相同图片
val query = this.query(
collection,
arrayOf(MediaStore.Images.Media._ID, @Suppress("DEPRECATION") MediaStore.Images.Media.DATA),
"${@Suppress("DEPRECATION") MediaStore.Images.Media.DATA} == ?",
arrayOf(imagePath), null
)
query?.use {
while (it.moveToNext()) {
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val id = it.getLong(idColumn)
val existsUri = ContentUris.withAppendedId(collection, id)
Log.v(TAG, "query: path: $imagePath exists uri: $existsUri")
return existsUri
}
}
return null
}

View File

@@ -47,18 +47,22 @@ object LogUtil {
e(tag, message + "\t\t" + cause, filePrinter)
}
@JvmStatic
fun d(tag: String, message: String, filePrinter: Boolean = false) {
log(Log.DEBUG, tag, message+" #thread:${Thread.currentThread().name}", filePrinter)
}
@JvmStatic
fun i(tag: String, message: String, filePrinter: Boolean = false) {
log(Log.INFO, tag, message, filePrinter)
}
@JvmStatic
fun v(tag: String, message: String, filePrinter: Boolean = false) {
log(Log.VERBOSE, tag, message, filePrinter)
}
@JvmStatic
fun w(tag: String, message: String, filePrinter: Boolean = false) {
log(Log.WARN, tag, message, filePrinter)
}