feat:完成预留活动(模版消息)公屏
This commit is contained in:
@@ -5,6 +5,7 @@ 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_GUARDIAN_PLANET;
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_GUARDIAN_PLANET;
|
||||||
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_RED_PACKAGE;
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_RED_PACKAGE;
|
||||||
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ROOM_ALBUM;
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ROOM_ALBUM;
|
||||||
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ROOM_TEMPLATE;
|
||||||
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ME;
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ME;
|
||||||
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L1;
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L1;
|
||||||
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L2;
|
import static com.yizhuan.xchat_android_core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L2;
|
||||||
@@ -145,6 +146,7 @@ import com.yizhuan.xchat_android_core.im.custom.bean.RoomReceivedLuckyGiftAttach
|
|||||||
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTipAttachment;
|
import com.yizhuan.xchat_android_core.im.custom.bean.RoomTipAttachment;
|
||||||
import com.yizhuan.xchat_android_core.im.custom.bean.TarotAttachment;
|
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.im.custom.bean.TarotMsgBean;
|
||||||
|
import com.yizhuan.xchat_android_core.im.custom.bean.TemplateMessageAttachment;
|
||||||
import com.yizhuan.xchat_android_core.im.custom.bean.User;
|
import com.yizhuan.xchat_android_core.im.custom.bean.User;
|
||||||
import com.yizhuan.xchat_android_core.im.custom.bean.VipMessageAttachment;
|
import com.yizhuan.xchat_android_core.im.custom.bean.VipMessageAttachment;
|
||||||
import com.yizhuan.xchat_android_core.im.custom.bean.WelcomeAttachment;
|
import com.yizhuan.xchat_android_core.im.custom.bean.WelcomeAttachment;
|
||||||
@@ -255,6 +257,7 @@ public class MessageView extends FrameLayout {
|
|||||||
private OnClick onClick;
|
private OnClick onClick;
|
||||||
|
|
||||||
private OnMsgLongClickListener onLongClickListener;
|
private OnMsgLongClickListener onLongClickListener;
|
||||||
|
private TemplateMessageAdapter templateMessageAdapter;
|
||||||
|
|
||||||
public MessageView(Context context) {
|
public MessageView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@@ -435,7 +438,17 @@ public class MessageView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private TemplateMessageAdapter getTemplateMessageAdapter() {
|
||||||
|
if (templateMessageAdapter == null) {
|
||||||
|
templateMessageAdapter = new TemplateMessageAdapter(uid -> {
|
||||||
|
if (clickConsumer != null) {
|
||||||
|
Single.just(String.valueOf(uid)).subscribe(clickConsumer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return templateMessageAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCurrentRoomReceiveNewMsg(List<ChatRoomMessage> messages) {
|
public void onCurrentRoomReceiveNewMsg(List<ChatRoomMessage> messages) {
|
||||||
@@ -619,6 +632,19 @@ public class MessageView extends FrameLayout {
|
|||||||
builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @param drawable -icon url
|
||||||
|
* @return -返回一個spannableStringBuilder
|
||||||
|
*/
|
||||||
|
public SpannableBuilder appendImg(String drawable, Object what) {
|
||||||
|
if (TextUtils.isEmpty(drawable)) return this;
|
||||||
|
int start = builder.length();
|
||||||
|
builder.append("-");
|
||||||
|
CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable);
|
||||||
|
builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param drawable -icon url
|
* @param drawable -icon url
|
||||||
@@ -635,6 +661,16 @@ public class MessageView extends FrameLayout {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SpannableBuilder append(String drawable, int width, int height, Object what) {
|
||||||
|
if (TextUtils.isEmpty(drawable)) return this;
|
||||||
|
int start = builder.length();
|
||||||
|
builder.append("-");
|
||||||
|
CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable, width, height);
|
||||||
|
builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文本和背景分離的情況
|
* 文本和背景分離的情況
|
||||||
*/
|
*/
|
||||||
@@ -676,6 +712,16 @@ public class MessageView extends FrameLayout {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SpannableBuilder append(String imgUrl, int height, Object what) {
|
||||||
|
if (TextUtils.isEmpty(imgUrl)) return this;
|
||||||
|
int start = builder.length();
|
||||||
|
builder.append("-");
|
||||||
|
builder.setSpan(new CustomAutoWidthImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, imgUrl, height)
|
||||||
|
, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param drawable -icon
|
* @param drawable -icon
|
||||||
* @param width 寬
|
* @param width 寬
|
||||||
@@ -1036,6 +1082,13 @@ public class MessageView extends FrameLayout {
|
|||||||
setRoomAlbumMsg(chatRoomMessage, baseViewHolder);
|
setRoomAlbumMsg(chatRoomMessage, baseViewHolder);
|
||||||
} else if (first == CUSTOM_MSG_GUARDIAN_PLANET) {
|
} else if (first == CUSTOM_MSG_GUARDIAN_PLANET) {
|
||||||
setGuardianPlanetMsg(chatRoomMessage, tvContent);
|
setGuardianPlanetMsg(chatRoomMessage, tvContent);
|
||||||
|
} else if (first == CUSTOM_MSG_ROOM_TEMPLATE) {
|
||||||
|
TemplateMessageAttachment templateMessageAttachment = (TemplateMessageAttachment) chatRoomMessage.getAttachment();
|
||||||
|
if (templateMessageAttachment != null) {
|
||||||
|
getTemplateMessageAdapter().convert(tvContent, templateMessageAttachment.getTemplateMessage());
|
||||||
|
} else {
|
||||||
|
getTemplateMessageAdapter().convert(tvContent, null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tvContent.setTextColor(Color.WHITE);
|
tvContent.setTextColor(Color.WHITE);
|
||||||
tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip));
|
tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip));
|
||||||
|
@@ -0,0 +1,133 @@
|
|||||||
|
package com.yizhuan.erban.avroom.widget
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import android.view.View
|
||||||
|
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.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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2024/2/22 17:20
|
||||||
|
* Desc:模版消息适配器
|
||||||
|
**/
|
||||||
|
class TemplateMessageAdapter(val listener: Listener) {
|
||||||
|
|
||||||
|
fun convert(textView: TextView, attachment: TemplateMessage?) {
|
||||||
|
if (attachment == null) {
|
||||||
|
textView.text = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val nodeList = attachment.getNodeList()
|
||||||
|
val textBuilder = MessageView.SpannableBuilder(textView)
|
||||||
|
nodeList.forEach {
|
||||||
|
if (it is TemplateNode.NormalNode) {
|
||||||
|
val textColor = parseColor(it.textColor)
|
||||||
|
if (textColor != null) {
|
||||||
|
textBuilder.append(it.text, ForegroundColorSpan(textColor))
|
||||||
|
} else {
|
||||||
|
textBuilder.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(textView.context, it.content)
|
||||||
|
val list = ArrayList<Any>()
|
||||||
|
if (textColor != null) {
|
||||||
|
list.add(ForegroundColorSpan(textColor))
|
||||||
|
}
|
||||||
|
if (clickSpan != null) {
|
||||||
|
list.add(clickSpan)
|
||||||
|
}
|
||||||
|
textBuilder.append(text, *list.toArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateMessage.Content.IMAGE -> {
|
||||||
|
val image = it.content.image
|
||||||
|
val width = it.content.width ?: 0
|
||||||
|
val height = it.content.height ?: 0
|
||||||
|
val clickSpan = createClickSpan(textView.context, it.content)
|
||||||
|
if (height > 0 && width == 0) {
|
||||||
|
if (clickSpan != null) {
|
||||||
|
textBuilder.append(
|
||||||
|
image,
|
||||||
|
UiUtils.dip2px(height.toFloat()),
|
||||||
|
clickSpan
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
textBuilder.append(image, UiUtils.dip2px(height.toFloat()))
|
||||||
|
}
|
||||||
|
} else if (height > 0 && width > 0) {
|
||||||
|
if (clickSpan != null) {
|
||||||
|
textBuilder.append(
|
||||||
|
image,
|
||||||
|
UiUtils.dip2px(width.toFloat()),
|
||||||
|
UiUtils.dip2px(height.toFloat()), clickSpan
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
textBuilder.append(
|
||||||
|
image,
|
||||||
|
UiUtils.dip2px(width.toFloat()),
|
||||||
|
UiUtils.dip2px(height.toFloat())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (clickSpan != null) {
|
||||||
|
textBuilder.appendImg(image, clickSpan)
|
||||||
|
} else {
|
||||||
|
textBuilder.appendImg(image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textView.text = textBuilder.build()
|
||||||
|
textView.setOnClickListener(null)
|
||||||
|
textView.movementMethod = LinkMovementMethod()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createClickSpan(
|
||||||
|
context: Context,
|
||||||
|
content: TemplateMessage.Content
|
||||||
|
): OriginalDrawStatusClickSpan? {
|
||||||
|
val skipType = content.getSkipType()
|
||||||
|
val skipUri = content.getSkipUri()
|
||||||
|
if (skipType > 0 && !skipUri.isNullOrEmpty()) {
|
||||||
|
return object : OriginalDrawStatusClickSpan() {
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) {
|
||||||
|
listener.onShowUserCard(skipUri)
|
||||||
|
} else {
|
||||||
|
CommonJumpHelper.bannerJump(context, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseColor(color: String?): Int? {
|
||||||
|
try {
|
||||||
|
return Color.parseColor(color)
|
||||||
|
} catch (e: java.lang.Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onShowUserCard(uid: String)
|
||||||
|
}
|
||||||
|
}
|
@@ -31,6 +31,10 @@ public class BannerInfo implements Parcelable, Serializable, IRouterData {
|
|||||||
* routerhandler跳转规则
|
* routerhandler跳转规则
|
||||||
*/
|
*/
|
||||||
public final static transient int SKIP_TYPE_ROUTER = 5;
|
public final static transient int SKIP_TYPE_ROUTER = 5;
|
||||||
|
/**
|
||||||
|
* 房间用户资料卡
|
||||||
|
*/
|
||||||
|
public final static transient int SKIP_TYPE_ROOM_USER_CARD = 6;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bannerId:1 //id
|
bannerId:1 //id
|
||||||
|
@@ -12,7 +12,9 @@ interface IRouterData : Serializable {
|
|||||||
|
|
||||||
fun getSkipType(): Int
|
fun getSkipType(): Int
|
||||||
|
|
||||||
|
@Deprecated("SkipType==5时用到该值,后台讲这种已经没用到了")
|
||||||
fun getRouterType(): String?
|
fun getRouterType(): String?
|
||||||
|
|
||||||
|
@Deprecated("SkipType==5时用到该值,后台讲这种已经没用到了")
|
||||||
fun getRouterValue(): String?
|
fun getRouterValue(): String?
|
||||||
}
|
}
|
@@ -1009,6 +1009,14 @@ public final class IMNetEaseManager {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CUSTOM_MSG_ROOM_TEMPLATE:
|
||||||
|
switch (second){
|
||||||
|
case CUSTOM_MSG_ROOM_TEMPLATE_SUB_ROOM:
|
||||||
|
case CUSTOM_MSG_ROOM_TEMPLATE_SUB_ALL_ROOM:
|
||||||
|
addMessages(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CUSTOM_MSG_RADISH:
|
case CUSTOM_MSG_RADISH:
|
||||||
RoomBoxPrizeAttachment boxPrizeAttachment = ((RoomBoxPrizeAttachment) msg.getAttachment());
|
RoomBoxPrizeAttachment boxPrizeAttachment = ((RoomBoxPrizeAttachment) msg.getAttachment());
|
||||||
UserInfo userInfo = UserModel.get().getCacheLoginUserInfo();
|
UserInfo userInfo = UserModel.get().getCacheLoginUserInfo();
|
||||||
|
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yizhuan.xchat_android_core.bean
|
||||||
|
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2024/2/22 18:36
|
||||||
|
* Desc:
|
||||||
|
**/
|
||||||
|
class I18N : HashMap<String, String>(), Serializable {
|
||||||
|
/**
|
||||||
|
* 获取优先显示文本
|
||||||
|
*/
|
||||||
|
fun getFirstText(): String? {
|
||||||
|
// 目前应用只支持繁体,后续支持其他语言,这里需要调整
|
||||||
|
val content = get("zh-TW")
|
||||||
|
return if (content.isNullOrEmpty()) {
|
||||||
|
this.values.firstOrNull()
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -659,6 +659,12 @@ public class CustomAttachParser implements MsgAttachmentParser {
|
|||||||
attachment = new RoomAlbumAttachment();
|
attachment = new RoomAlbumAttachment();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CustomAttachment.CUSTOM_MSG_ROOM_TEMPLATE:
|
||||||
|
if (second == CustomAttachment.CUSTOM_MSG_ROOM_TEMPLATE_SUB_ROOM
|
||||||
|
|| second == CustomAttachment.CUSTOM_MSG_ROOM_TEMPLATE_SUB_ALL_ROOM) {
|
||||||
|
attachment = new TemplateMessageAttachment(first, second);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogUtils.e(ResUtil.getString(R.string.custom_bean_customattachparser_01) + first + " second=" + second);
|
LogUtils.e(ResUtil.getString(R.string.custom_bean_customattachparser_01) + first + " second=" + second);
|
||||||
break;
|
break;
|
||||||
|
@@ -485,6 +485,10 @@ public class CustomAttachment implements MsgAttachment {
|
|||||||
public static final int CUSTOM_MSG_ROOM_ALBUM = 101;
|
public static final int CUSTOM_MSG_ROOM_ALBUM = 101;
|
||||||
public static final int CUSTOM_MSG_ROOM_ALBUM_SUB = 1011;
|
public static final int CUSTOM_MSG_ROOM_ALBUM_SUB = 1011;
|
||||||
|
|
||||||
|
// 模版消息
|
||||||
|
public static final int CUSTOM_MSG_ROOM_TEMPLATE = 103;
|
||||||
|
public static final int CUSTOM_MSG_ROOM_TEMPLATE_SUB_ROOM = 1031;
|
||||||
|
public static final int CUSTOM_MSG_ROOM_TEMPLATE_SUB_ALL_ROOM = 1032;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义消息附件的类型,根据该字段区分不同的自定义消息
|
* 自定义消息附件的类型,根据该字段区分不同的自定义消息
|
||||||
|
@@ -0,0 +1,132 @@
|
|||||||
|
package com.yizhuan.xchat_android_core.im.custom.bean
|
||||||
|
|
||||||
|
import com.chuhai.utils.StringUtils
|
||||||
|
import com.yizhuan.xchat_android_core.bean.I18N
|
||||||
|
import com.yizhuan.xchat_android_core.home.bean.IRouterData
|
||||||
|
import java.io.Serializable
|
||||||
|
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 {
|
||||||
|
|
||||||
|
private val nodeList: List<TemplateNode>? = null
|
||||||
|
|
||||||
|
fun getNodeList(): List<TemplateNode> {
|
||||||
|
var nodeList = this.nodeList
|
||||||
|
if (nodeList == null) {
|
||||||
|
nodeList = parseNodes()
|
||||||
|
}
|
||||||
|
return nodeList
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转化为方便渲染的节点列表
|
||||||
|
private fun parseNodes(): List<TemplateNode> {
|
||||||
|
val templateText = template?.getFirstText()
|
||||||
|
val contentList = this.contents
|
||||||
|
val defTextColor = this.textColor
|
||||||
|
if (templateText.isNullOrEmpty()) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
if (contentList.isNullOrEmpty()) {
|
||||||
|
return listOf(
|
||||||
|
TemplateNode.NormalNode(
|
||||||
|
text = templateText,
|
||||||
|
textColor = defTextColor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val list = ArrayList<TemplateNode>()
|
||||||
|
StringUtils.split(
|
||||||
|
content = templateText,
|
||||||
|
pattern = Pattern.compile("\\{.+?\\}"),
|
||||||
|
onNormalNode = {
|
||||||
|
list.add(
|
||||||
|
TemplateNode.NormalNode(
|
||||||
|
text = it,
|
||||||
|
textColor = defTextColor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onMatchNode = { text ->
|
||||||
|
val content = contentList.firstOrNull {
|
||||||
|
"{${it.key}}" == text
|
||||||
|
}
|
||||||
|
if (content?.type == Content.TEXT && content.textColor.isNullOrEmpty()) {
|
||||||
|
// 默认文本色
|
||||||
|
content.textColor = textColor
|
||||||
|
}
|
||||||
|
if (content != null) {
|
||||||
|
list.add(
|
||||||
|
TemplateNode.SpecialNode(
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Content(
|
||||||
|
/**
|
||||||
|
* 公共字段
|
||||||
|
*/
|
||||||
|
val key: String? = null,
|
||||||
|
// TEXT,IMAGE
|
||||||
|
val type: String? = null,
|
||||||
|
val skipType: Int? = null,
|
||||||
|
val skipContent: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本相关字段(type=TEXT)
|
||||||
|
*/
|
||||||
|
val text: I18N? = null,
|
||||||
|
var textColor: String? = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片相关字段(type=IMAGE)
|
||||||
|
*/
|
||||||
|
val image: String? = null,
|
||||||
|
val width: Int? = null,
|
||||||
|
val height: Int? = null
|
||||||
|
) : Serializable, IRouterData {
|
||||||
|
|
||||||
|
override fun getSkipType(): Int {
|
||||||
|
return skipType ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRouterType(): String? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRouterValue(): String? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSkipUri(): String? {
|
||||||
|
return skipContent
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TEXT = "TEXT"
|
||||||
|
const val IMAGE = "IMAGE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TemplateNode : Serializable {
|
||||||
|
data class NormalNode(
|
||||||
|
var text: String,
|
||||||
|
var textColor: String? = null
|
||||||
|
) : TemplateNode
|
||||||
|
|
||||||
|
data class SpecialNode(
|
||||||
|
var content: Content
|
||||||
|
) : TemplateNode
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
package com.yizhuan.xchat_android_core.im.custom.bean
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject
|
||||||
|
import com.google.gson.Gson
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2024/2/22 17:28
|
||||||
|
* Desc:
|
||||||
|
**/
|
||||||
|
class TemplateMessageAttachment : CustomAttachment {
|
||||||
|
|
||||||
|
constructor() : super()
|
||||||
|
constructor(first: Int, second: Int) : super(first, second)
|
||||||
|
|
||||||
|
private var templateMessage: TemplateMessage? = null
|
||||||
|
|
||||||
|
fun getTemplateMessage() = templateMessage
|
||||||
|
|
||||||
|
override fun parseData(data: JSONObject?) {
|
||||||
|
super.parseData(data)
|
||||||
|
if (data != null) {
|
||||||
|
try {
|
||||||
|
templateMessage = Gson().fromJson<TemplateMessage>(
|
||||||
|
data.toJSONString(),
|
||||||
|
TemplateMessage::class.java
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
package com.chuhai.utils
|
||||||
|
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Max on 2/10/21 4:56 PM
|
||||||
|
* Desc:字符串工具
|
||||||
|
*/
|
||||||
|
object StringUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拆分字符串(根据匹配规则,按顺序拆分出来)
|
||||||
|
* @param pattern 匹配节点的规则模式
|
||||||
|
* @param onNormalNode<节点内容> 普通节点
|
||||||
|
* @param onMatchNode<节点内容> 匹配节点
|
||||||
|
*/
|
||||||
|
fun split(
|
||||||
|
content: String,
|
||||||
|
pattern: Pattern,
|
||||||
|
onNormalNode: (String) -> Unit,
|
||||||
|
onMatchNode: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
onNormalNode.invoke(content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val matcher = pattern.matcher(content)
|
||||||
|
// 最后一个匹配项的结束位置
|
||||||
|
var lastItemEnd = 0
|
||||||
|
var noMatch = true
|
||||||
|
while (matcher.find()) {
|
||||||
|
noMatch = false
|
||||||
|
// 匹配元素的开启位置
|
||||||
|
val start = matcher.start()
|
||||||
|
// 匹配元素的结束位置
|
||||||
|
val end = matcher.end()
|
||||||
|
// 匹配元素的文本
|
||||||
|
val text = matcher.group()
|
||||||
|
// 匹配元素的对应索引
|
||||||
|
// logD("split() start:$start ,end:$end ,text:$text")
|
||||||
|
if (start > lastItemEnd) {
|
||||||
|
// 普通节点
|
||||||
|
val nodeContent = content.substring(lastItemEnd, start)
|
||||||
|
onNormalNode.invoke(nodeContent)
|
||||||
|
}
|
||||||
|
// 匹配节点显示内容
|
||||||
|
onMatchNode.invoke(text)
|
||||||
|
lastItemEnd = end
|
||||||
|
}
|
||||||
|
if (lastItemEnd > 0 && lastItemEnd < content.length) {
|
||||||
|
// 最后的匹配项不是尾部(追加最后的尾部)
|
||||||
|
val nodeContent = content.substring(lastItemEnd, content.length)
|
||||||
|
onNormalNode.invoke(nodeContent)
|
||||||
|
}
|
||||||
|
if (noMatch) {
|
||||||
|
// 无匹配
|
||||||
|
onNormalNode.invoke(content)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user