对接Socket
This commit is contained in:
parent
7600f0d041
commit
a50e97f2ed
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="21" />
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -9,6 +9,7 @@
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name="com.tenlionsoft.baselib.base.App"
|
||||
|
68
app/src/main/java/com/tenlionsoft/aimz_k/ConvertBeanUtils.kt
Normal file
68
app/src/main/java/com/tenlionsoft/aimz_k/ConvertBeanUtils.kt
Normal file
@ -0,0 +1,68 @@
|
||||
package com.tenlionsoft.aimz_k
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.tenlionsoft.aimz_k.model.CoverSealedBean
|
||||
import com.tenlionsoft.aimz_k.model.MsgBean
|
||||
import com.tenlionsoft.aimz_k.model.MsgConvertBean
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
|
||||
object ConvertBeanUtils {
|
||||
|
||||
fun covertBean(str: String): CoverSealedBean {
|
||||
val gson = Gson()
|
||||
val sBean = gson.fromJson(str, MsgConvertBean::class.java)
|
||||
var type: Int = -1
|
||||
if (sBean.messageType != ProjectConfig.MSG_STATUS) {
|
||||
when (sBean.messageType) {
|
||||
ProjectConfig.MSG_TEXT -> type = MsgTypeStateEnum.MSG_FROM_OTHER_TXT
|
||||
ProjectConfig.MSG_IMG -> type = MsgTypeStateEnum.MSG_FROM_OTHER_IMG
|
||||
ProjectConfig.MSG_FILE -> type = MsgTypeStateEnum.MSG_FROM_OTHER_FILE
|
||||
ProjectConfig.MSG_VIDEO -> type = MsgTypeStateEnum.MSG_FROM_OTHER_MOVIE
|
||||
}
|
||||
return CoverSealedBean.Msg(
|
||||
MsgBean(
|
||||
messageId = sBean.messageId,
|
||||
messageType = sBean.messageType,
|
||||
metadata = sBean.metadata,
|
||||
receiverId = sBean.receiver.receiverId,
|
||||
receiverType = sBean.receiver.receiverType,
|
||||
senderType = sBean.sender.senderType,
|
||||
senderId = sBean.sender.senderId,
|
||||
body = sBean.body,
|
||||
msgType = type,
|
||||
timestamp = sBean.timestamp,
|
||||
status = sBean.status,
|
||||
customMessageType = ""
|
||||
)
|
||||
)
|
||||
} else {
|
||||
return CoverSealedBean.StateBean(sBean)
|
||||
}
|
||||
}
|
||||
|
||||
fun convertBeanToMsgBean(cBean: MsgConvertBean): MsgBean {
|
||||
var type: Int = -1
|
||||
when (cBean.messageType) {
|
||||
ProjectConfig.MSG_TEXT -> type = MsgTypeStateEnum.MSG_TO_OTHER_TXT
|
||||
ProjectConfig.MSG_IMG -> type = MsgTypeStateEnum.MSG_TO_OTHER_IMG
|
||||
ProjectConfig.MSG_FILE -> type = MsgTypeStateEnum.MSG_TO_OTHER_FILE
|
||||
ProjectConfig.MSG_VIDEO -> type = MsgTypeStateEnum.MSG_TO_OTHER_MOVIE
|
||||
}
|
||||
return MsgBean(
|
||||
messageId = cBean.messageId,
|
||||
messageType = cBean.messageType,
|
||||
metadata = cBean.metadata,
|
||||
receiverId = cBean.receiver.receiverId,
|
||||
receiverType = cBean.receiver.receiverType,
|
||||
senderType = cBean.sender.senderType,
|
||||
senderId = cBean.sender.senderId,
|
||||
body = cBean.body,
|
||||
msgType = type,
|
||||
timestamp = cBean.timestamp,
|
||||
status = cBean.status,
|
||||
customMessageType = ""
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -12,13 +12,14 @@ class CategoryAdapter(
|
||||
private val viewModel: MsgViewModel
|
||||
) : BaseBindingAdapter<MsgCategoryBean, ItemCategoryBinding>(datas) {
|
||||
|
||||
override fun getItemBinding(parent: ViewGroup,viewType:Int): ItemCategoryBinding {
|
||||
override fun getItemBinding(parent: ViewGroup, viewType: Int): ItemCategoryBinding {
|
||||
return ItemCategoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
}
|
||||
|
||||
override fun bindItem(holder: BaseViewHolder<ItemCategoryBinding>, position: Int) {
|
||||
holder.binding.pos = position
|
||||
holder.binding.item = list[position]
|
||||
holder.binding.size = if (list.isNotEmpty()) list.size - 1 else 0
|
||||
holder.binding.root.setOnClickListener {
|
||||
viewModel.onItemClickListener?.onItemClick(list[position])
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_TXT -> {
|
||||
return ItemMsgMyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
}//发送文本
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_my, parent, false);
|
||||
// holder = new MsgMyTextHolder(itemView);
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_TXT -> {
|
||||
return ItemMsgOtherBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -32,9 +30,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//收到文本信息
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_other, parent, false);
|
||||
// holder = new MsgMyOtherHolder(itemView);
|
||||
// break;
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_MOVIE -> {
|
||||
return ItemMsgMyVideoBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -42,9 +37,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//发送视频
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_my_video, parent, false);
|
||||
// holder = new MsgVideoHolder(itemView);
|
||||
// break;
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_MOVIE -> {
|
||||
return ItemMsgOtherVideoBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -52,9 +44,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//收到视频
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_other_video, parent, false);
|
||||
// holder = new MsgVideoHolder(itemView);
|
||||
// break;
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_IMG -> {
|
||||
return ItemMsgMyImgBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -62,9 +51,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//发送图片
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_my_img, parent, false);
|
||||
// holder = new MsgImageHolder(itemView);
|
||||
// break;
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_IMG -> {
|
||||
return ItemMsgOtherImgBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -72,9 +58,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//收到图片
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_other_img, parent, false);
|
||||
// holder = new MsgImageHolder(itemView);
|
||||
// break;
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_VOICE -> {
|
||||
return ItemMsgMyAudioBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -82,9 +65,6 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//语音
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_my_audio, parent, false);
|
||||
// holder = new MsgAudioHolder(itemView);
|
||||
// break;
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_VOICE -> {
|
||||
return ItemMsgOtherAudioBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
@ -92,18 +72,14 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
false
|
||||
)
|
||||
}//语音
|
||||
// itemView = LayoutInflater.from(mContext).inflate(R.layout.item_msg_other_audio, parent, false);
|
||||
// holder = new MsgAudioHolder(itemView);
|
||||
// break;
|
||||
else -> {
|
||||
// return BaseViewHolder()
|
||||
throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return list.get(position).msgType
|
||||
return list[position].msgType!!
|
||||
}
|
||||
|
||||
override fun bindItem(holder: BaseViewHolder<ViewDataBinding>, position: Int) {
|
||||
@ -112,42 +88,42 @@ class ChatMsgAdapter(var datas: List<MsgBean>) :
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_TXT -> {
|
||||
(holder.binding as ItemMsgMyBinding).pos = position
|
||||
(holder.binding as ItemMsgMyBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgMyBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgMyBinding).state = list[position].status
|
||||
}//发送文本
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_TXT -> {
|
||||
(holder.binding as ItemMsgOtherBinding).pos = position
|
||||
(holder.binding as ItemMsgOtherBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgOtherBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgOtherBinding).state = list[position].status
|
||||
}//收到文本信息
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_MOVIE -> {
|
||||
(holder.binding as ItemMsgMyVideoBinding).pos = position
|
||||
(holder.binding as ItemMsgMyVideoBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgMyVideoBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgMyVideoBinding).state = list[position].status
|
||||
}//发送视频
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_MOVIE -> {
|
||||
(holder.binding as ItemMsgOtherVideoBinding).pos = position
|
||||
(holder.binding as ItemMsgOtherVideoBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgOtherVideoBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgOtherVideoBinding).state = list[position].status
|
||||
}//收到视频
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_IMG -> {
|
||||
(holder.binding as ItemMsgMyImgBinding).pos = position
|
||||
(holder.binding as ItemMsgMyImgBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgMyImgBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgMyImgBinding).state = list[position].status
|
||||
}//发送图片
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_IMG -> {
|
||||
(holder.binding as ItemMsgOtherImgBinding).pos = position
|
||||
(holder.binding as ItemMsgOtherImgBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgOtherImgBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgOtherImgBinding).state = list[position].status
|
||||
}//收到图片
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_VOICE -> {
|
||||
(holder.binding as ItemMsgMyAudioBinding).pos = position
|
||||
(holder.binding as ItemMsgMyAudioBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgMyAudioBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgMyAudioBinding).state = list[position].status
|
||||
}//语音
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_VOICE -> {
|
||||
(holder.binding as ItemMsgOtherAudioBinding).pos = position
|
||||
(holder.binding as ItemMsgOtherAudioBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgOtherAudioBinding).state = list[position].sendState
|
||||
(holder.binding as ItemMsgOtherAudioBinding).state = list[position].status
|
||||
}//语音
|
||||
else -> {
|
||||
throw IllegalArgumentException("Invalid view type")
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.tenlionsoft.aimz_k.model
|
||||
|
||||
sealed class CoverSealedBean {
|
||||
data class StateBean(val data: MsgConvertBean) : CoverSealedBean()
|
||||
data class Msg(val msgBean: MsgBean) : CoverSealedBean()
|
||||
|
||||
}
|
@ -2,33 +2,72 @@ package com.tenlionsoft.aimz_k.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.TypeConverters
|
||||
import java.io.Serializable
|
||||
|
||||
|
||||
//{
|
||||
// "body": "{\"msg\":\"\",\"statusType\":\"SUCCESS_SEND\"}",
|
||||
// "customMessageType": "",
|
||||
// "messageId": "1730344667596",
|
||||
// "messageType": "STATUS",
|
||||
// "metadata": "",
|
||||
// "receiver": {
|
||||
// "receiverId": "1",
|
||||
// "receiverType": "SINGLE_USER"
|
||||
//},
|
||||
// "sender": {
|
||||
// "senderId": "system",
|
||||
// "senderType": "SYSTEM"
|
||||
//},
|
||||
// "timestamp": 1730344666322
|
||||
//}
|
||||
|
||||
//发送格式
|
||||
//messageId: `${datetime}`,
|
||||
//timestamp: datetime,
|
||||
//messageType: 'MSG_TEXT',
|
||||
//body: JSON.stringify({content: chat.send.value}),
|
||||
//sender: {
|
||||
// senderId: chat.senderId,
|
||||
// senderType: 'ANONYMOUS'
|
||||
//},
|
||||
//receiver: {
|
||||
// receiverId: chat.receiverId,
|
||||
// receiverType: 'SINGLE_USER'
|
||||
//},
|
||||
//metadata: '',
|
||||
//status: 'PENDING',
|
||||
|
||||
|
||||
@Entity(tableName = "db_msg")
|
||||
data class MsgBean(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long,
|
||||
@ColumnInfo(name = "type")
|
||||
var type: Int, //消息类型
|
||||
@ColumnInfo(name = "isSystem")
|
||||
var isSystem: Boolean, //是否为系统信息
|
||||
@ColumnInfo(name = "from")
|
||||
var from: String, //来源,系统消息为:SYSTEM 非系统消息为UserID
|
||||
@ColumnInfo(name = "to")
|
||||
var to: String, //去处 系统消息为appId 非系统消息为userId
|
||||
@ColumnInfo(name = "body")
|
||||
var body: String, //消息体
|
||||
var id: Long = 0,
|
||||
@ColumnInfo(name = "messageId")
|
||||
var messageId: String?, //消息唯一ID
|
||||
@ColumnInfo(name = "messageType")
|
||||
var messageType: String?, //消息类型
|
||||
@ColumnInfo(name = "customMessageType")
|
||||
var customMessageType: String?, //预留
|
||||
@ColumnInfo(name = "metadata")
|
||||
var metadata: String?,
|
||||
@ColumnInfo(name = "receiverId")
|
||||
var receiverId: String?, //接受人ID
|
||||
@ColumnInfo(name = "receiverType")
|
||||
var receiverType: String?, //接受人Type
|
||||
@ColumnInfo(name = "senderId")
|
||||
var senderId: String?, //发送人ID
|
||||
@ColumnInfo(name = "senderType")
|
||||
var senderType: String?, //发送人类型
|
||||
@ColumnInfo(name = "timestamp")
|
||||
var timestamp: Long,
|
||||
@ColumnInfo(name = "sendState")
|
||||
var sendState: Int, //发送状态 11发送中 12发送失败 13发送成功
|
||||
@ColumnInfo(name = "fromName")
|
||||
var fromName: String, //来源名称
|
||||
var timestamp: Long?, //时间戳
|
||||
@ColumnInfo(name = "body")
|
||||
var body: String?, //消息体
|
||||
@ColumnInfo(name = "msgType")
|
||||
var msgType: Int,
|
||||
var msgType: Int?,
|
||||
@ColumnInfo(name = "status")
|
||||
var status: String? //发送状态 11发送中 12发送失败 13发送成功
|
||||
|
||||
/**
|
||||
* 信息类型
|
||||
@ -48,7 +87,4 @@ data class MsgBean(
|
||||
* 151 我发送给其他人的文件信息
|
||||
* 152 其他人发送给我的文件信息
|
||||
*/
|
||||
) : Serializable {
|
||||
@Ignore
|
||||
var msgWhat: Long = 0L
|
||||
}
|
||||
) : Serializable
|
@ -5,24 +5,55 @@ import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
|
||||
//@ColumnInfo(name = "messageId")
|
||||
//var messageId: String?, //消息唯一ID
|
||||
//@ColumnInfo(name = "messageType")
|
||||
//var messageType: String?, //消息类型
|
||||
//@ColumnInfo(name = "customMessageType")
|
||||
//var customMessageType: String?, //预留
|
||||
//@ColumnInfo(name = "metadata")
|
||||
//var metadata: String?,
|
||||
//@ColumnInfo(name = "receiverId")
|
||||
//var receiverId: String?, //接受人ID
|
||||
//@ColumnInfo(name = "receiverType")
|
||||
//var receiverType: String?, //接受人Type
|
||||
//@ColumnInfo(name = "senderId")
|
||||
//var senderId: String?, //发送人ID
|
||||
//@ColumnInfo(name = "senderType")
|
||||
//var senderType: String?, //发送人类型
|
||||
//@ColumnInfo(name = "timestamp")
|
||||
//var timestamp: Long?, //时间戳
|
||||
//@ColumnInfo(name = "body")
|
||||
//var body: String?, //消息体
|
||||
//@ColumnInfo(name = "msgType")
|
||||
//var msgType: Int?,
|
||||
//@ColumnInfo(name = "status")
|
||||
//var status: String? //发送状态 11发送中 12发送失败 13发送成功
|
||||
|
||||
@Entity(tableName = "db_category")
|
||||
data class MsgCategoryBean(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
@ColumnInfo(name = "avatar")
|
||||
var avatar: String,
|
||||
@ColumnInfo(name = "from")
|
||||
var from: String, //来源,系统消息为:SYSTEM 非系统消息为UserID
|
||||
@ColumnInfo(name = "to")
|
||||
var to: String, //去处 系统消息为appId 非系统消息为userId
|
||||
@ColumnInfo(name = "messageId")
|
||||
var messageId: String?, //消息ID
|
||||
@ColumnInfo(name = "messageType")
|
||||
var messageType: String, //消息类型
|
||||
@ColumnInfo(name = "receiverId")
|
||||
var receiverId: String?, //接受人ID
|
||||
@ColumnInfo(name = "receiverType")
|
||||
var receiverType: String?, //接受人Type
|
||||
@ColumnInfo(name = "senderId")
|
||||
var senderId: String?, //发送人ID
|
||||
@ColumnInfo(name = "senderType")
|
||||
var senderType: String?, //发送人类型
|
||||
@ColumnInfo(name = "timestamp")
|
||||
var timestamp: Long, // 时间戳
|
||||
@ColumnInfo(name = "sendState")
|
||||
var sendState: Int, //发送状态 11发送中 12发送失败 13发送成功
|
||||
@ColumnInfo(name = "fromName")
|
||||
var fromName: String, //来源名称
|
||||
var timestamp: Long?, //时间戳
|
||||
@ColumnInfo(name = "body")
|
||||
var body: String,
|
||||
@ColumnInfo(name = "isRead") //是否回复
|
||||
var isRead: Boolean,
|
||||
var body: String?, //消息体
|
||||
@ColumnInfo(name = "msgType")
|
||||
var msgType: Int?, //用来在列表中判断显示
|
||||
@ColumnInfo(name = "status")
|
||||
var status: String?, //消息状态
|
||||
) : Serializable
|
@ -16,6 +16,12 @@ interface MsgCategoryDao {
|
||||
@Query("SELECT * FROM db_category")
|
||||
fun getAllCategory(): List<MsgCategoryBean>
|
||||
|
||||
/**
|
||||
* 根据发送人ID获取
|
||||
*/
|
||||
@Query("SELECT * FROM db_category WHERE senderId=:senderId")
|
||||
fun getCategoryBySenderId(senderId: String): MsgCategoryBean?
|
||||
|
||||
/**
|
||||
* 根据ID获取消息
|
||||
*
|
||||
@ -31,7 +37,7 @@ interface MsgCategoryDao {
|
||||
* @param from
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_category WHERE `from`=(:from)")
|
||||
@Query("SELECT * FROM db_category WHERE `senderId`=(:from)")
|
||||
fun getCategoryByFrom(from: String?): List<MsgCategoryBean>
|
||||
|
||||
|
||||
@ -48,7 +54,7 @@ interface MsgCategoryDao {
|
||||
/**
|
||||
* 清空与某个人的聊天记录
|
||||
*/
|
||||
@Query("DELETE FROM db_category WHERE `from`=(:from) AND `to`=(:to) OR `from`=(:to) AND `to`=(:from)")
|
||||
@Query("DELETE FROM db_category WHERE `senderId`=(:from) AND receiverId=(:to) OR `senderId`=(:to) AND receiverId=(:from)")
|
||||
fun delChatHistory(from: String?, to: String?)
|
||||
|
||||
/**
|
||||
@ -79,4 +85,16 @@ interface MsgCategoryDao {
|
||||
*/
|
||||
@Query("DELETE FROM db_category")
|
||||
fun delAllMsg()
|
||||
|
||||
/**
|
||||
* 根据发送人的ID插入或者更新
|
||||
*/
|
||||
fun updateOrInsert(senderId: String, msgBean: MsgBean)
|
||||
|
||||
/**
|
||||
* 更新 消息体 时间戳 状态
|
||||
* @Query("UPDATE db_msg SET status = :status WHERE messageId = :messageId")
|
||||
*/
|
||||
@Query("UPDATE db_category SET status= :status , body=:body , timestamp=:time WHERE senderId=:senderId")
|
||||
fun updateCategory(senderId: String, status:String,body:String,time:Long)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.tenlionsoft.aimz_k.model
|
||||
|
||||
abstract class MsgCategoryDaoImpl : MsgCategoryDao {
|
||||
|
||||
override fun updateOrInsert(senderId: String, msgBean: MsgBean) {
|
||||
val bean = getCategoryBySenderId(senderId)
|
||||
if (bean == null) {
|
||||
//需要转换成MsgCategoryBean
|
||||
|
||||
// insertMsg(msgBean)
|
||||
} else {
|
||||
updateCategory(senderId, msgBean.status!!, msgBean.body!!, msgBean.timestamp!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.tenlionsoft.aimz_k.model
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class MsgConvertBean(
|
||||
val body: String,
|
||||
val customMessageType: String,
|
||||
val messageId: String,
|
||||
val messageType: String,
|
||||
val metadata: String,
|
||||
val `receiver`: Receiver,
|
||||
val sender: Sender,
|
||||
val timestamp: Long,
|
||||
val status: String
|
||||
) : Serializable
|
||||
|
||||
public data class Receiver(
|
||||
val receiverId: String?,
|
||||
val receiverType: String?
|
||||
) : Serializable
|
||||
|
||||
public data class Sender(
|
||||
val senderId: String?,
|
||||
val senderType: String?
|
||||
) : Serializable
|
||||
|
||||
//"{\"msg\":\"\",\"statusType\":\"SUCCESS_SEND\"}",
|
||||
data class BodyContent(
|
||||
val content: String?,
|
||||
val msg: String?,
|
||||
val statusType: String?
|
||||
) : Serializable
|
@ -7,6 +7,12 @@ import androidx.room.Query
|
||||
|
||||
@Dao
|
||||
interface MsgDao {
|
||||
/**
|
||||
* 更新信息状态
|
||||
*/
|
||||
@Query("UPDATE db_msg SET status = :status WHERE messageId = :messageId")
|
||||
fun updateStatus(messageId: String, status: String)
|
||||
|
||||
/**
|
||||
* 获取全部信息
|
||||
*
|
||||
@ -24,13 +30,17 @@ interface MsgDao {
|
||||
@Query("SELECT * FROM db_msg WHERE id =(:id) ")
|
||||
fun getMsgById(id: String?): List<MsgBean?>?
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 根据信息来源查询消息
|
||||
*
|
||||
* @param from
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_msg WHERE `from`=(:from)")
|
||||
@Query("SELECT * FROM db_msg WHERE `senderId`=(:from)")
|
||||
fun getMsgByFrom(from: String?): List<MsgBean?>?
|
||||
|
||||
/**
|
||||
@ -39,7 +49,7 @@ interface MsgDao {
|
||||
* @param to
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_msg WHERE `to` =(:to)")
|
||||
@Query("SELECT * FROM db_msg WHERE `receiverId` =(:to)")
|
||||
fun getMsgByTo(to: String?): List<MsgBean?>?
|
||||
|
||||
|
||||
@ -51,13 +61,13 @@ interface MsgDao {
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_msg WHERE `from`=(:form) ORDER BY timestamp LIMIT (((:page)-1)*(:pageSize)),(:pageSize)")
|
||||
@Query("SELECT * FROM db_msg WHERE `senderId`=(:form) ORDER BY timestamp LIMIT (((:page)-1)*(:pageSize)),(:pageSize)")
|
||||
fun getMsgByPage(form: String?, pageSize: Int, page: Int): List<MsgBean?>?
|
||||
|
||||
/**
|
||||
* 查询与单人的聊天记录
|
||||
*/
|
||||
@Query("SELECT * FROM db_msg t1 WHERE t1.id IN (SELECT id FROM db_msg WHERE `from`=(:form) AND `to`=(:to) OR `from`=(:to) AND `to`=(:form) ORDER BY timestamp DESC LIMIT (((:page)-1)*(:pageSize)),(:pageSize)) ORDER by t1.timestamp ASC")
|
||||
@Query("SELECT * FROM db_msg t1 WHERE t1.id IN (SELECT id FROM db_msg WHERE `senderId`=(:form) AND `receiverId`=(:to) OR `senderId`=(:to) AND `receiverId`=(:form) ORDER BY timestamp DESC LIMIT (((:page)-1)*(:pageSize)),(:pageSize)) ORDER by t1.timestamp ASC")
|
||||
fun getMsgByFromOrToPage(
|
||||
form: String?,
|
||||
to: String?,
|
||||
@ -68,7 +78,7 @@ interface MsgDao {
|
||||
/**
|
||||
* 清空与某个人的聊天记录
|
||||
*/
|
||||
@Query("DELETE FROM db_msg WHERE `from`=(:from) AND `to`=(:to) OR `from`=(:to) AND `to`=(:from)")
|
||||
@Query("DELETE FROM db_msg WHERE `senderId`=(:from) AND `receiverId`=(:to) OR `receiverId`=(:to) AND `senderId`=(:from)")
|
||||
fun delChatHistory(from: String?, to: String?)
|
||||
|
||||
/**
|
||||
|
@ -6,9 +6,6 @@ import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_FROM_OTHER_IMG
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_FROM_OTHER_MOVIE
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_FROM_OTHER_TXT
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_FROM_OTHER_VOICE
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_SEND_FAIL
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_SEND_ING
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_SEND_SUCCESS
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_TO_OTHER_FILE
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_TO_OTHER_IMG
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum.MSG_TO_OTHER_MOVIE
|
||||
@ -28,9 +25,6 @@ object MsgTypeStateEnum {
|
||||
const val MSG_FROM_OTHER_FILE: Int = 152 // * 152 其他人发送给我的文件信息
|
||||
const val MSG_TO_OTHER_HREF: Int = 161 // * 161 我发送给其他人的文件信息
|
||||
const val MSG_FROM_OTHER_HREF: Int = 162 // * 162 其他人发送给我的文件信息
|
||||
const val MSG_SEND_ING: Int = 1001//11 //发送中
|
||||
const val MSG_SEND_FAIL: Int = 1002//12 //发送失败
|
||||
const val MSG_SEND_SUCCESS: Int = 1003////发送成功
|
||||
|
||||
}
|
||||
|
||||
@ -46,9 +40,6 @@ object MsgTypeStateEnum {
|
||||
MSG_FROM_OTHER_IMG,
|
||||
MSG_FROM_OTHER_MOVIE,
|
||||
MSG_FROM_OTHER_FILE,
|
||||
MSG_SEND_ING,
|
||||
MSG_SEND_FAIL,
|
||||
MSG_SEND_SUCCESS
|
||||
)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class MsgState
|
@ -22,7 +22,14 @@ interface UserApi {
|
||||
@Headers("Content-Type: application/json", "Accept: application/json", "projectName:usercenter")
|
||||
@POST("api/jwt/login")
|
||||
suspend fun doLogin(@Body user: RequestBody): BaseSuccessBean
|
||||
|
||||
/**
|
||||
* 登陆Socket系统
|
||||
* http://192.168.0.26:8888/system/api/anonymous/login
|
||||
*
|
||||
*/
|
||||
@Headers("Content-Type: application/json", "Accept: application/json", "projectName:usercenter")
|
||||
@POST("api/anonymous/login")
|
||||
suspend fun doLoginSocket(@Body user: RequestBody): BaseSuccessBean
|
||||
|
||||
/**
|
||||
* 获取App版本
|
||||
|
@ -1,9 +1,11 @@
|
||||
package com.tenlionsoft.aimz_k.page.activity
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.util.Log
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
@ -13,6 +15,7 @@ import com.tenlionsoft.aimz_k.databinding.ActivityChatBinding
|
||||
import com.tenlionsoft.aimz_k.model.PickerType
|
||||
import com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel
|
||||
import com.tenlionsoft.baselib.base.BaseActivity
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.widget.wheel.WheelView
|
||||
|
||||
/**
|
||||
@ -23,6 +26,7 @@ class ChatActivity : BaseActivity() {
|
||||
private val chatPageViewModel: ChatPageViewModel by lazy {
|
||||
ViewModelProvider(this)[ChatPageViewModel::class.java]
|
||||
}
|
||||
private lateinit var mLocalReceiver: LocalReceiver
|
||||
|
||||
private val filePicker = FilePicker.getInstance(this)
|
||||
override fun bindView() {
|
||||
@ -93,67 +97,37 @@ class ChatActivity : BaseActivity() {
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
// chatPageViewModel.showReplyLayout.observe(this) {
|
||||
// if (it) {
|
||||
// hideSoftKeyboard()
|
||||
// }
|
||||
// }
|
||||
// chatPageViewModel.showEmojiLayout.observe(this) {
|
||||
// if (it) {
|
||||
// hideSoftKeyboard()
|
||||
// }
|
||||
// }
|
||||
// chatPageViewModel.showChooseLayout.observe(this) {
|
||||
// if (it) {
|
||||
// hideSoftKeyboard()
|
||||
// }
|
||||
// }
|
||||
|
||||
// rootView = findViewById(android.R.id.content)
|
||||
// rootView.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
// val r = Rect()
|
||||
// rootView.getWindowVisibleDisplayFrame(r)
|
||||
// val screenHeight = rootView.rootView.height
|
||||
// val heightDiff = screenHeight - (r.bottom - r.top)
|
||||
// Log.e("ChatActivity", "bindView: ${heightDiff}")
|
||||
// if (heightDiff > 100) {
|
||||
// chatPageViewModel.showEmojiLayout.value = false
|
||||
// chatPageViewModel.showReplyLayout.value = false
|
||||
// chatPageViewModel.showChooseLayout.value = false
|
||||
// }
|
||||
// }
|
||||
registerLocalReceiver()
|
||||
}
|
||||
|
||||
|
||||
private fun registerLocalReceiver() {
|
||||
mLocalReceiver = LocalReceiver()
|
||||
val intentFilter = IntentFilter()
|
||||
intentFilter.addAction(ProjectConfig.A_S_MSG_RECEIVER)
|
||||
registerReceiver(mLocalReceiver, intentFilter)
|
||||
}
|
||||
|
||||
private fun unRegisterLocalReceiver() {
|
||||
unregisterReceiver(mLocalReceiver)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
unRegisterLocalReceiver()
|
||||
}
|
||||
|
||||
inner class LocalReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
ProjectConfig.A_S_MSG_RECEIVER -> {
|
||||
val msg = intent.getStringExtra("msg")
|
||||
Log.e("LocalReceiver", "onReceive: ${msg}")
|
||||
chatPageViewModel.receiveMsg(msg)
|
||||
}//接收到信息
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//XXPermissions.with(this)
|
||||
//// 申请单个权限
|
||||
//.permission(Permission.RECORD_AUDIO)
|
||||
//// 申请多个权限
|
||||
//.permission(Permission.Group.CALENDAR)
|
||||
//// 设置权限请求拦截器(局部设置)
|
||||
////.interceptor(new PermissionInterceptor())
|
||||
//// 设置不触发错误检测机制(局部设置)
|
||||
////.unchecked()
|
||||
//.request(object : OnPermissionCallback {
|
||||
//
|
||||
// override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) {
|
||||
// if (!allGranted) {
|
||||
// toast("获取部分权限成功,但部分权限未正常授予")
|
||||
// return
|
||||
// }
|
||||
// toast("获取录音和日历权限成功")
|
||||
// }
|
||||
//
|
||||
// override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
|
||||
// if (doNotAskAgain) {
|
||||
// toast("被永久拒绝授权,请手动授予录音和日历权限")
|
||||
// // 如果是被永久拒绝就跳转到应用权限系统设置页面
|
||||
// XXPermissions.startPermissionActivity(context, permissions)
|
||||
// } else {
|
||||
// toast("获取录音和日历权限失败")
|
||||
// }
|
||||
// }
|
||||
//})
|
||||
|
@ -40,8 +40,7 @@ class LoginActivity : BaseActivity() {
|
||||
}
|
||||
loginPageViewModel.isLoginSuccess.observe(this) {
|
||||
if (it) {
|
||||
// startActivity(Intent(this@LoginActivity, MainActivity::class.java))
|
||||
startActivity(Intent(this@LoginActivity, ChatActivity::class.java))
|
||||
startActivity(Intent(this@LoginActivity, MainActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
@ -8,30 +8,26 @@ import android.content.IntentFilter
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.tenlionsoft.aimz_k.R
|
||||
import com.tenlionsoft.aimz_k.adapter.VpAdapter
|
||||
import com.tenlionsoft.aimz_k.databinding.ActivityMainBinding
|
||||
import com.tenlionsoft.aimz_k.net.UserApi
|
||||
import com.tenlionsoft.aimz_k.page.fragments.CenterFragment
|
||||
import com.tenlionsoft.aimz_k.page.fragments.MineFragment
|
||||
import com.tenlionsoft.aimz_k.page.fragments.MsgFragment
|
||||
import com.tenlionsoft.aimz_k.viewmodel.MainPageViewModel
|
||||
import com.tenlionsoft.baselib.base.BaseActivity
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.net.DownloadApkService
|
||||
import com.tenlionsoft.baselib.net.ExParse
|
||||
import com.tenlionsoft.baselib.net.RetrofitClient
|
||||
import com.tenlionsoft.baselib.utils.AppUtils
|
||||
import com.tenlionsoft.baselib.utils.DensityUtils
|
||||
import com.tenlionsoft.baselib.utils.LogUtils
|
||||
import com.tenlionsoft.baselib.utils.ToastUtils
|
||||
import com.tenlionsoft.baselib.widget.CenterProgressUpdateView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -51,10 +47,14 @@ class MainActivity : BaseActivity() {
|
||||
private lateinit var mLocalReceiver: MainBroadcastReceiver
|
||||
private var mUpdateView: CenterProgressUpdateView? = null
|
||||
private var mApkFile: File? = null
|
||||
|
||||
private var onSocketConnectListener: OnSocketConnectListener? = null
|
||||
private val mainPageViewModel: MainPageViewModel by lazy {
|
||||
ViewModelProvider(this)[MainPageViewModel::class.java]
|
||||
}
|
||||
|
||||
override fun bindView() {
|
||||
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
|
||||
mBinding.mainModel = mainPageViewModel
|
||||
initView();
|
||||
}
|
||||
|
||||
@ -108,26 +108,10 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
})
|
||||
registerLocalReceiver()
|
||||
checkAppVersion()
|
||||
}
|
||||
|
||||
private fun checkAppVersion() {
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val appVersion = RetrofitClient.getInstance(this@MainActivity)
|
||||
.create(UserApi::class.java)
|
||||
.doCheckAppVersion(ProjectConfig.APP_VERSION_ID)
|
||||
if (appVersion.versioncode.isNotEmpty()) {
|
||||
val isNeedUpdate = AppUtils.checkcode(appVersion.versioncode)
|
||||
if (isNeedUpdate) {
|
||||
startDownloadApk()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
ExParse.parse(e)
|
||||
}
|
||||
mainPageViewModel.doCheckAppVersion(this@MainActivity)
|
||||
mainPageViewModel.isNeedDownload.observe(this) {
|
||||
if (it) {
|
||||
startDownloadApk()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,16 +129,17 @@ class MainActivity : BaseActivity() {
|
||||
filter.addAction(ProjectConfig.ACTION_UPDATE_ERROR) //下载失败
|
||||
filter.addAction(ProjectConfig.ACTION_UPDATE_PROGRESS) //进度更新
|
||||
filter.addAction(ProjectConfig.ACTION_UPDATE_START) //开始下载App
|
||||
filter.addAction(ProjectConfig.A_S_CONNECTED)//socket连接成功
|
||||
filter.addAction(ProjectConfig.A_S_FAIL)//socket连接失败
|
||||
filter.addAction(ProjectConfig.A_S_DISCONNECT)//socket连接断开
|
||||
registerReceiver(mLocalReceiver, filter)
|
||||
}
|
||||
|
||||
private suspend fun startDownloadApk() {
|
||||
withContext(Dispatchers.Main) {
|
||||
ToastUtils.normal("检测到新版本,开始下载")
|
||||
val intent = Intent(this@MainActivity, DownloadApkService::class.java)
|
||||
intent.putExtra(ProjectConfig.APK_DOWNLOAD_URL, ProjectConfig.APP_DOWNLOAD_URL)
|
||||
startService(intent)
|
||||
}
|
||||
private fun startDownloadApk() {
|
||||
ToastUtils.normal("检测到新版本,开始下载")
|
||||
val intent = Intent(this@MainActivity, DownloadApkService::class.java)
|
||||
intent.putExtra(ProjectConfig.APK_DOWNLOAD_URL, ProjectConfig.APP_DOWNLOAD_URL)
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
|
||||
@ -186,15 +171,25 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
registerLocalReceiver()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
unRegisterLocalReceiver()
|
||||
}
|
||||
|
||||
|
||||
fun setOnSocketListener(onSocketConnectListener: OnSocketConnectListener) {
|
||||
this.onSocketConnectListener = onSocketConnectListener
|
||||
}
|
||||
|
||||
inner class MainBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
Log.e("MainBroadcastReceiver", "onReceive: ${intent?.action}")
|
||||
when (intent?.action) {
|
||||
ProjectConfig.ACTION_UPDATE_START -> {
|
||||
showUpdateProgress()
|
||||
@ -215,10 +210,27 @@ class MainActivity : BaseActivity() {
|
||||
val apkFile = intent.getSerializableExtra("apkFile") as File?
|
||||
installApk(apkFile!!)
|
||||
}//下载成功
|
||||
ProjectConfig.A_S_CONNECTED -> {
|
||||
onSocketConnectListener?.onListener(ProjectConfig.A_S_CONNECTED)
|
||||
}//socket 连接成功
|
||||
ProjectConfig.A_S_FAIL -> {
|
||||
onSocketConnectListener?.onListener(ProjectConfig.A_S_FAIL)
|
||||
}//连接失败
|
||||
ProjectConfig.A_S_MSG_RECEIVER -> {
|
||||
val extra = intent.getStringExtra(ProjectConfig.MSG_TEXT)
|
||||
if (!extra.isNullOrEmpty()) {
|
||||
onSocketConnectListener?.onReceiverMsg(extra)
|
||||
}
|
||||
}//接收到信息
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnSocketConnectListener {
|
||||
fun onListener(status: String)
|
||||
fun onReceiverMsg(msg: String)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.tenlionsoft.aimz_k.page.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
@ -8,18 +9,21 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tenlionsoft.aimz_k.R
|
||||
import com.tenlionsoft.aimz_k.databinding.FragmentMsgBinding
|
||||
import com.tenlionsoft.aimz_k.model.MsgCategoryBean
|
||||
import com.tenlionsoft.aimz_k.page.activity.ChatActivity
|
||||
import com.tenlionsoft.aimz_k.page.activity.MainActivity
|
||||
import com.tenlionsoft.aimz_k.services.SocketService
|
||||
import com.tenlionsoft.aimz_k.viewmodel.MsgViewModel
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.widget.LoadingDialog
|
||||
|
||||
class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener {
|
||||
class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener,
|
||||
MainActivity.OnSocketConnectListener {
|
||||
private lateinit var mMsgBinding: FragmentMsgBinding
|
||||
private var mActivity: FragmentActivity? = null
|
||||
private var mActivity: MainActivity? = null
|
||||
private var mLoading: LoadingDialog? = null;
|
||||
|
||||
companion object {
|
||||
@ -43,7 +47,6 @@ class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener {
|
||||
container,
|
||||
false
|
||||
);
|
||||
mActivity = activity
|
||||
mMsgBinding.llSearchLayout.llSearchLayout.setOnClickListener {
|
||||
startActivity(Intent(this@MsgFragment.context, ChatActivity::class.java))
|
||||
}
|
||||
@ -66,6 +69,34 @@ class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener {
|
||||
mMsgBinding.srlMsgs.finishRefresh()
|
||||
mMsgBinding.srlMsgs.finishLoadMore()
|
||||
}
|
||||
viewModel.isLogining.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
mMsgBinding.llSearchLayout.tvSocketStatus.text = "登陆中..."
|
||||
mMsgBinding.llSearchLayout.ivSocketStatus.visibility = View.GONE
|
||||
mMsgBinding.llSearchLayout.pbSocketLoading.visibility = View.VISIBLE
|
||||
toStartService()
|
||||
} else {
|
||||
mMsgBinding.llSearchLayout.ivSocketStatus.visibility = View.VISIBLE
|
||||
mMsgBinding.llSearchLayout.ivSocketStatus.setImageResource(R.drawable.shp_circle_green)
|
||||
mMsgBinding.llSearchLayout.tvSocketStatus.visibility = View.GONE
|
||||
mMsgBinding.llSearchLayout.pbSocketLoading.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
//登陆socket
|
||||
viewModel.doLoginWebsocket()
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
if (context is MainActivity) {
|
||||
mActivity = context
|
||||
mActivity!!.setOnSocketListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
//开启service
|
||||
private fun toStartService() {
|
||||
mActivity?.startService(Intent(mActivity!!, SocketService::class.java))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,4 +107,25 @@ class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener {
|
||||
startActivity(Intent(mActivity, ChatActivity::class.java))
|
||||
}
|
||||
|
||||
//监听socket连接状态
|
||||
override fun onListener(status: String) {
|
||||
Log.e("MsgFragment", "onListener: ${status}")
|
||||
when (status) {
|
||||
ProjectConfig.A_S_CONNECTED -> {
|
||||
viewModel.isLogining.value = false
|
||||
}//连接成功
|
||||
ProjectConfig.A_S_FAIL -> {
|
||||
viewModel.isLogining.value = true
|
||||
}//连接失败
|
||||
ProjectConfig.A_S_DISCONNECT -> {}//连接断开
|
||||
}
|
||||
}
|
||||
|
||||
//接收到socket信息
|
||||
override fun onReceiverMsg(msg: String) {
|
||||
if (msg.isNotEmpty()) {
|
||||
viewModel.fromMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +1,30 @@
|
||||
package com.tenlionsoft.aimz_k.services
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import com.tenlionsoft.aimz_k.R
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.tenlionsoft.aimz_k.socket.WsManager
|
||||
import com.tenlionsoft.baselib.contacts.NetConfig
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.utils.SpUtils
|
||||
|
||||
|
||||
/**
|
||||
* Socket service
|
||||
*/
|
||||
class SocketService : Service() {
|
||||
class SocketService : Service(), WsManager.MsgCallBack {
|
||||
private var mWsManager: WsManager? = null
|
||||
private val gson = Gson()
|
||||
private lateinit var mLocalReceiver: LocalReceiver
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
@ -33,30 +40,40 @@ class SocketService : Service() {
|
||||
|
||||
@SuppressLint("ForegroundServiceType")
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
val builder: Notification.Builder
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder = Notification.Builder(this, ProjectConfig.NOTIFY_CHANNEL_ID)
|
||||
} else {
|
||||
builder = Notification.Builder(this)
|
||||
}
|
||||
builder.setContentTitle("Ai秒著")
|
||||
.setContentText("聊天已经登陆")
|
||||
.setSmallIcon(R.drawable.app_logo_small)
|
||||
val notification: Notification = builder.build()
|
||||
startForeground(startId, notification)
|
||||
// val builder: Notification.Builder
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// builder = Notification.Builder(this, ProjectConfig.NOTIFY_CHANNEL_ID)
|
||||
// } else {
|
||||
// builder = Notification.Builder(this)
|
||||
// }
|
||||
// builder.setContentTitle("Ai秒著")
|
||||
// .setContentText("聊天已经登陆")
|
||||
// .setSmallIcon(R.drawable.app_logo_small)
|
||||
// val notification: Notification = builder.build()
|
||||
// startForeground(startId, notification)
|
||||
|
||||
this.startSocket();//开启Socket
|
||||
registerLocalReceiver()
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
|
||||
private fun registerLocalReceiver() {
|
||||
val intentFilter = IntentFilter()
|
||||
mLocalReceiver = LocalReceiver()
|
||||
intentFilter.addAction(ProjectConfig.A_S_MSG_SEND)//发送消息
|
||||
registerReceiver(mLocalReceiver, intentFilter)
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启链接socket
|
||||
*/
|
||||
fun startSocket() {
|
||||
private fun startSocket() {
|
||||
if (mWsManager == null) {
|
||||
mWsManager = WsManager.Builder(applicationContext)
|
||||
.wsUrl(ProjectConfig.SOCKET_MSG_SECRET)
|
||||
.wsUrl(NetConfig.WS_URL + "?token=" + SpUtils.getToken())
|
||||
.needReconnect(true)
|
||||
.addCallBack(this)
|
||||
.build()
|
||||
}
|
||||
if (!mWsManager!!.isWsConnected()) {
|
||||
@ -65,7 +82,7 @@ class SocketService : Service() {
|
||||
|
||||
}
|
||||
|
||||
fun stopSocket() {
|
||||
private fun stopSocket() {
|
||||
if (mWsManager != null && mWsManager!!.isWsConnected()) {
|
||||
mWsManager!!.stopConnect();
|
||||
mWsManager = null;
|
||||
@ -78,6 +95,28 @@ class SocketService : Service() {
|
||||
|
||||
override fun onDestroy() {
|
||||
stopSocket();
|
||||
unregisterReceiver(mLocalReceiver)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
inner class LocalReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
ProjectConfig.A_S_MSG_SEND -> {
|
||||
val msgConvertBean = intent.getSerializableExtra("msgBean")
|
||||
val msg = gson.toJson(msgConvertBean)
|
||||
mWsManager?.sendMessage(msg)
|
||||
}//发送消息
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//socket接收到信息
|
||||
override fun onCallBackMsg(str: String) {
|
||||
Log.e("SocketService", "接收信息: ${str}")
|
||||
val intent = Intent(ProjectConfig.A_S_MSG_RECEIVER)
|
||||
intent.putExtra("msg", str)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
}
|
@ -40,8 +40,10 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
private var mLock: Lock = ReentrantLock()
|
||||
private val wsMainHandler: Handler = Handler(Looper.getMainLooper())
|
||||
private var reconnectCount = 5 //重连次数
|
||||
private var mMsgCallBack: MsgCallBack? = builder.callBack
|
||||
private val reconnectRunnable = Runnable {
|
||||
if (reconnectCount < 10) {
|
||||
//重新连接
|
||||
val intent = Intent()
|
||||
// intent.setAction(PathConfig.ACTION_SOCKET_RELINK)
|
||||
mContext.sendBroadcast(intent)
|
||||
@ -50,43 +52,12 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
|
||||
|
||||
private val mWebSocketListener: WebSocketListener = object : WebSocketListener() {
|
||||
private fun buildMsgBean(type: Int, body: String): String {
|
||||
// val message: AppSocketMessage = AppSocketMessage()
|
||||
// message.setType(type)
|
||||
// val userId: String = GlobalProvider.getString(mContext, "userId")
|
||||
// message.setFrom(userId)
|
||||
// message.setTo(userId)
|
||||
//
|
||||
// var bodyBean: BaseSocketBodyBean? = null
|
||||
// when (type) {
|
||||
// 1000 -> {
|
||||
// bodyBean = SocketRegisterBodyBean()
|
||||
// (bodyBean as SocketRegisterBodyBean?).setSessionId(body)
|
||||
// }
|
||||
// }
|
||||
// val gson = Gson()
|
||||
// val s = gson.toJson(bodyBean)
|
||||
// message.setBody(s)
|
||||
// val messageStr = gson.toJson(message)
|
||||
// return messageStr
|
||||
return body
|
||||
|
||||
}
|
||||
|
||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||
mWebSocket = webSocket
|
||||
setCurrentStatus(WsStatus.CONNECTED)
|
||||
connected()
|
||||
//注册websocket
|
||||
// TODO val sessionId: String = GlobalProvider.getString(mContext, StatusCode.SESSION_ID)
|
||||
var sessionId: String = ""
|
||||
LogUtils.e("Session_Id==$sessionId")
|
||||
val messageStr = buildMsgBean(1000, sessionId)
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) { //主线程
|
||||
val isSend = sendMessage(messageStr)
|
||||
} else { //子线程
|
||||
val isSend = sendMessage(messageStr)
|
||||
}
|
||||
sendBroadcast(ProjectConfig.A_S_CONNECTED)
|
||||
}
|
||||
|
||||
override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
|
||||
@ -124,9 +95,8 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||
try {
|
||||
tryReconnect()
|
||||
val intent = Intent()
|
||||
//TODO intent.setAction(PathConfig.ACTION_MSG_SOCKET_FAIL)
|
||||
mContext!!.sendBroadcast(intent)
|
||||
//发送失败广播
|
||||
sendBroadcast(ProjectConfig.A_S_FAIL)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@ -152,9 +122,16 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
mLock.unlock()
|
||||
}
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
//发送广播
|
||||
private fun sendBroadcast(action: String) {
|
||||
val intent = Intent(action)
|
||||
mContext.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
override fun getWebSocket(): WebSocket? {
|
||||
return mWebSocket
|
||||
}
|
||||
@ -291,10 +268,7 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
private fun isNetworkConnected(context: Context?): Boolean {
|
||||
if (context != null) {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val activeNetwork: Network? = cm.getActiveNetwork()
|
||||
if (activeNetwork == null) {
|
||||
return false
|
||||
}
|
||||
val activeNetwork: Network = cm.activeNetwork ?: return false
|
||||
val capabilities = cm.getNetworkCapabilities(activeNetwork)
|
||||
return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
} else {
|
||||
@ -303,33 +277,20 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
}
|
||||
|
||||
private fun sendNotify(jsonStr: String) {
|
||||
// if (!TextUtils.isEmpty(jsonStr)) {
|
||||
// LogUtils.e("收到消息:$jsonStr")
|
||||
// val broadCstIntent = Intent()
|
||||
// if (PathConfig.IS_SECRET) {
|
||||
// try {
|
||||
// val msg: String =
|
||||
// AesUtil.aesCommonDecoder(PathConfig.SOCKET_MSG_SECRET, jsonStr)
|
||||
// broadCstIntent.setAction(PathConfig.ACTION_FROM_SOCKET_PUSH_MSG)
|
||||
// broadCstIntent.putExtra(StatusCode.PUSH_DATA_KEY, msg)
|
||||
// mContext!!.sendBroadcast(broadCstIntent)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// } else {
|
||||
// broadCstIntent.setAction(PathConfig.ACTION_FROM_SOCKET_PUSH_MSG)
|
||||
// broadCstIntent.putExtra(StatusCode.PUSH_DATA_KEY, jsonStr)
|
||||
// mContext!!.sendBroadcast(broadCstIntent)
|
||||
// }
|
||||
// }
|
||||
if (jsonStr.isNotEmpty()) {
|
||||
mMsgCallBack?.onCallBackMsg(jsonStr)
|
||||
}
|
||||
}
|
||||
|
||||
interface MsgCallBack {
|
||||
fun onCallBackMsg(str: String)
|
||||
}
|
||||
|
||||
class Builder(val mContext: Context) {
|
||||
lateinit var wsUrl: String
|
||||
var needReconnect: Boolean = true
|
||||
var mOkHttpClient: OkHttpClient? = null
|
||||
|
||||
var callBack: MsgCallBack? = null
|
||||
fun wsUrl(url: String): Builder {
|
||||
wsUrl = url
|
||||
return this
|
||||
@ -345,6 +306,11 @@ class WsManager private constructor(val builder: Builder) : IWsManager {
|
||||
return this
|
||||
}
|
||||
|
||||
fun addCallBack(callBack: MsgCallBack): Builder {
|
||||
this.callBack = callBack
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): WsManager {
|
||||
return WsManager(this)
|
||||
}
|
||||
|
@ -1,27 +1,45 @@
|
||||
package com.tenlionsoft.aimz_k.viewmodel
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.atwa.filepicker.result.FileMeta
|
||||
import com.atwa.filepicker.result.ImageMeta
|
||||
import com.atwa.filepicker.result.VideoMeta
|
||||
import com.google.gson.Gson
|
||||
import com.tenlionsoft.aimz_k.ConvertBeanUtils
|
||||
import com.tenlionsoft.aimz_k.model.BodyContent
|
||||
import com.tenlionsoft.aimz_k.model.CoverSealedBean
|
||||
import com.tenlionsoft.aimz_k.model.DbManager
|
||||
import com.tenlionsoft.aimz_k.model.MsgConvertBean
|
||||
import com.tenlionsoft.aimz_k.model.PickerType
|
||||
import com.tenlionsoft.aimz_k.model.Receiver
|
||||
import com.tenlionsoft.aimz_k.model.Sender
|
||||
import com.tenlionsoft.baselib.base.BaseViewModel
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.utils.SpUtils
|
||||
import com.tenlionsoft.baselib.utils.TimeUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ChatPageViewModel : BaseViewModel() {
|
||||
var txtMsg: String = ""
|
||||
val txtMsg = MutableLiveData<String>("")
|
||||
val showSendBtn = MutableLiveData(false)//显示/隐藏发送按钮
|
||||
val showEmojiLayout = MutableLiveData(false)//显示/隐藏emoji
|
||||
val showReplyLayout = MutableLiveData(false)//显示/隐藏快速回复
|
||||
val showChooseLayout = MutableLiveData(false)//显示/隐藏选择
|
||||
val chooseType = MutableLiveData<PickerType>()//选择文件类型
|
||||
private val mGson: Gson = Gson()
|
||||
|
||||
init {
|
||||
Log.e("ChatPageViewModel", "Init: ${showSendBtn.value}")
|
||||
}
|
||||
|
||||
fun onTxtChange(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
this.txtMsg = s.toString()
|
||||
this.txtMsg.value = s.toString()
|
||||
|
||||
showSendBtn.value = s.isNotEmpty()
|
||||
Log.e("ChatPageViewModel", "onTxtChange: ${showSendBtn.value}")
|
||||
@ -103,7 +121,87 @@ class ChatPageViewModel : BaseViewModel() {
|
||||
/**
|
||||
* 发送文本信息
|
||||
*/
|
||||
fun sendTxtMsg() {
|
||||
fun sendTxtMsg(v: View) {
|
||||
if (txtMsg.value!!.isNotEmpty()) {
|
||||
val intent = Intent(ProjectConfig.A_S_MSG_SEND)
|
||||
val b = buildSendBean()
|
||||
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val dao = DbManager.db.msgDao()
|
||||
val msgBean = ConvertBeanUtils.convertBeanToMsgBean(b)
|
||||
dao.insertMsg(msgBean)
|
||||
}
|
||||
}
|
||||
Log.e("ChatPageViewModel", "sendTxtMsg: ${b}")
|
||||
intent.putExtra("msgBean", b)
|
||||
v.context.sendBroadcast(intent)
|
||||
txtMsg.value = ""
|
||||
}
|
||||
|
||||
//TODO 刷新列表
|
||||
}
|
||||
|
||||
//收到消息
|
||||
fun receiveMsg(msg: String?) {
|
||||
if (!msg.isNullOrEmpty()) {
|
||||
val bean = ConvertBeanUtils.covertBean(msg)
|
||||
Log.e("ChatPageViewModel", "receiveMsg: ${bean}")
|
||||
when (bean) {
|
||||
//状态消息
|
||||
is CoverSealedBean.StateBean -> {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val dao = DbManager.db.msgDao()
|
||||
//TODO 并且更新Category表
|
||||
dao.updateStatus(
|
||||
bean.data.messageId,
|
||||
mGson.fromJson(bean.data.body, BodyContent::class.java).statusType!!
|
||||
)
|
||||
}
|
||||
//TODO 刷新列表
|
||||
}
|
||||
}
|
||||
//消息
|
||||
is CoverSealedBean.Msg -> {
|
||||
//插入信息表
|
||||
//并更新category表
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val msgDao = DbManager.db.msgDao()
|
||||
val cDao = DbManager.db.categoryDao()
|
||||
msgDao.insertMsg(bean.msgBean)
|
||||
cDao.updateOrInsert(bean.msgBean.senderId!!, bean.msgBean)
|
||||
}
|
||||
}
|
||||
//刷新列表
|
||||
|
||||
Log.e("ChatPageViewModel", "receiveMsg接收到消息: ${bean.msgBean}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun buildSendBean(): MsgConvertBean {
|
||||
val bodyBean = BodyContent(content = txtMsg.value, null, null)
|
||||
var body = mGson.toJson(bodyBean)
|
||||
return MsgConvertBean(
|
||||
body = body,
|
||||
customMessageType = "",
|
||||
messageId = TimeUtils.getNowDateMillis().toString(),
|
||||
messageType = ProjectConfig.MSG_TEXT,
|
||||
metadata = "",
|
||||
timestamp = TimeUtils.getNowDateMillis(),
|
||||
sender = Sender(
|
||||
senderId = SpUtils.getId(),
|
||||
senderType = ""
|
||||
),
|
||||
receiver = Receiver(
|
||||
receiverId = "2",
|
||||
receiverType = "SINGLE_USER"
|
||||
),
|
||||
status = ProjectConfig.MSG_SEND_ING,
|
||||
)
|
||||
}
|
||||
}
|
@ -37,7 +37,6 @@ class LoginPageViewModel : BaseViewModel() {
|
||||
}
|
||||
|
||||
fun doLogin() {
|
||||
isLoginSuccess.value = true
|
||||
val isLegal = checkParams();
|
||||
if (isLegal) {
|
||||
viewModelScope.launch {
|
||||
@ -56,12 +55,11 @@ class LoginPageViewModel : BaseViewModel() {
|
||||
userPwd,
|
||||
userName
|
||||
);
|
||||
|
||||
Log.e("LoginPageViewModel", "登陆前: Thread${Thread.currentThread().name}")
|
||||
val loginUserStr = gson.toJson(userBody)
|
||||
val body =
|
||||
loginUserStr.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||
val user = userApi.doLogin(body);
|
||||
Log.e("LoginPageViewModel", "login: ${user.code}")
|
||||
if (user.code == 200) {
|
||||
//登陆成功
|
||||
val token = JwtUtils.parseToken(user.data)
|
||||
@ -71,12 +69,16 @@ class LoginPageViewModel : BaseViewModel() {
|
||||
} else {
|
||||
//登陆成功
|
||||
//解析Token
|
||||
Log.e("LoginPageViewModel", "login: $token")
|
||||
Log.e("LoginPageViewModel", "login: ${token}")
|
||||
val appTokenUser = gson.fromJson(token, AppTokenUser::class.java)
|
||||
Log.e(
|
||||
"LoginPageViewModel",
|
||||
"Thread ${Thread.currentThread().name} login: UserId${appTokenUser.user.id}"
|
||||
)
|
||||
SpUtils.putPassword(userPwd)
|
||||
SpUtils.putAvatar(appTokenUser.user.avatar)
|
||||
SpUtils.putNickName(appTokenUser.user.nickname)
|
||||
SpUtils.putId(appTokenUser.user.id)
|
||||
SpUtils.putId(appTokenUser.user.userId)
|
||||
SpUtils.putEmail(appTokenUser.user.email)
|
||||
SpUtils.putUserName(appTokenUser.user.username)
|
||||
SpUtils.putPhone(appTokenUser.user.phone)
|
||||
|
@ -0,0 +1,39 @@
|
||||
package com.tenlionsoft.aimz_k.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tenlionsoft.aimz_k.net.UserApi
|
||||
import com.tenlionsoft.baselib.base.BaseViewModel
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.net.ExParse
|
||||
import com.tenlionsoft.baselib.net.RetrofitClient
|
||||
import com.tenlionsoft.baselib.utils.AppUtils
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainPageViewModel : BaseViewModel() {
|
||||
val isNeedDownload = MutableLiveData<Boolean>(false)
|
||||
|
||||
//校验Appversion
|
||||
fun doCheckAppVersion(context: Context) {
|
||||
viewModelScope.launch {
|
||||
getAppVersion(context)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getAppVersion(context: Context) {
|
||||
try {
|
||||
val appVersion = RetrofitClient.getInstance(context)
|
||||
.create(UserApi::class.java)
|
||||
.doCheckAppVersion(ProjectConfig.APP_VERSION_ID)
|
||||
if (appVersion.versioncode.isNotEmpty()) {
|
||||
val isNeedUpdate = AppUtils.checkcode(appVersion.versioncode)
|
||||
if (isNeedUpdate) {
|
||||
isNeedDownload.value = true
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
ExParse.parse(e)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +1,34 @@
|
||||
package com.tenlionsoft.aimz_k.viewmodel
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tenlionsoft.aimz_k.ConvertBeanUtils
|
||||
import com.tenlionsoft.aimz_k.adapter.CategoryAdapter
|
||||
import com.tenlionsoft.aimz_k.model.CoverSealedBean
|
||||
import com.tenlionsoft.aimz_k.model.DbManager
|
||||
import com.tenlionsoft.aimz_k.model.MsgCategoryBean
|
||||
import com.tenlionsoft.aimz_k.adapter.CategoryAdapter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class MsgViewModel : ViewModel() {
|
||||
private val _pwdList = MutableLiveData<List<MsgCategoryBean>>()
|
||||
var adapter: CategoryAdapter = CategoryAdapter(_pwdList.value ?: emptyList(),this)
|
||||
var adapter: CategoryAdapter = CategoryAdapter(_pwdList.value ?: emptyList(), this)
|
||||
var onItemClickListener: OnItemClickListener? = null
|
||||
|
||||
val isLogining = MutableLiveData<Boolean>(false)
|
||||
private var mCurrentPage: Int = 1
|
||||
var isHasMore: MutableLiveData<Boolean> = MutableLiveData<Boolean>().apply {
|
||||
value = false
|
||||
}
|
||||
var isHasMore: MutableLiveData<Boolean> = MutableLiveData<Boolean>(false)
|
||||
|
||||
init {
|
||||
Log.e("MsgViewModel", "Init:${_pwdList.value} ")
|
||||
getPwdList(true)
|
||||
getList(true)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
*/
|
||||
private fun getPwdList(isFirst: Boolean) {
|
||||
private fun getList(isFirst: Boolean) {
|
||||
viewModelScope.launch {
|
||||
if (isFirst) {
|
||||
_pwdList.value = emptyList()
|
||||
@ -46,7 +44,6 @@ class MsgViewModel : ViewModel() {
|
||||
}
|
||||
val updateData: List<MsgCategoryBean> = _pwdList.value!! + list
|
||||
_pwdList.value = updateData
|
||||
Log.e("MsgViewModel", "getPwdList: ${_pwdList.value}")
|
||||
adapter.setData(_pwdList.value!!)
|
||||
}
|
||||
}
|
||||
@ -64,14 +61,30 @@ class MsgViewModel : ViewModel() {
|
||||
* 加载更多
|
||||
*/
|
||||
fun loadMore() {
|
||||
getPwdList(false)
|
||||
getList(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 登陆websocket
|
||||
*/
|
||||
fun doLoginWebsocket() {
|
||||
isLogining.value = true
|
||||
}
|
||||
|
||||
//接收到信息
|
||||
fun fromMsg(msg: String) {
|
||||
val bean = ConvertBeanUtils.covertBean(msg)
|
||||
when (bean) {
|
||||
is CoverSealedBean.StateBean -> {}//消息状态
|
||||
is CoverSealedBean.Msg -> {}//消息
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新
|
||||
*/
|
||||
fun refresh() {
|
||||
getPwdList(true)
|
||||
getList(true)
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
|
@ -10,7 +10,7 @@ import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.tenlionsoft.aimz_k.R
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
|
||||
|
||||
object BindingUtils {
|
||||
@ -52,11 +52,11 @@ object BindingUtils {
|
||||
//发送中
|
||||
@BindingAdapter("isShowLoading")
|
||||
@JvmStatic
|
||||
fun sending(view: View, status: Int) {
|
||||
fun sending(view: View, status: String) {
|
||||
when (status) {
|
||||
MsgTypeStateEnum.MSG_SEND_SUCCESS -> view.visibility = View.GONE
|
||||
MsgTypeStateEnum.MSG_SEND_FAIL -> view.visibility = View.GONE
|
||||
MsgTypeStateEnum.MSG_SEND_ING -> view.visibility = View.VISIBLE
|
||||
ProjectConfig.MSG_SEND_SUCCESS -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_FAIL -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_ING -> view.visibility = View.VISIBLE
|
||||
else -> view.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
@ -64,11 +64,11 @@ object BindingUtils {
|
||||
//发送失败
|
||||
@BindingAdapter("isShowFail")
|
||||
@JvmStatic
|
||||
fun sendFail(view: View, status: Int) {
|
||||
fun sendFail(view: View, status: String) {
|
||||
when (status) {
|
||||
MsgTypeStateEnum.MSG_SEND_SUCCESS -> view.visibility = View.GONE
|
||||
MsgTypeStateEnum.MSG_SEND_FAIL -> view.visibility = View.GONE
|
||||
MsgTypeStateEnum.MSG_SEND_ING -> view.visibility = View.VISIBLE
|
||||
ProjectConfig.MSG_SEND_SUCCESS -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_FAIL -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_ING -> view.visibility = View.VISIBLE
|
||||
else -> view.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
5
app/src/main/res/drawable/shp_circle_green.xml
Normal file
5
app/src/main/res/drawable/shp_circle_green.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/green" />
|
||||
</shape>
|
@ -4,7 +4,8 @@
|
||||
|
||||
<data>
|
||||
|
||||
<import type="android.view.View"/>
|
||||
<import type="android.view.View" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel" />
|
||||
@ -125,7 +126,7 @@
|
||||
android:id="@+id/iv_send"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="30dp"
|
||||
android:onClick="@{()->viewModel.sendTxtMsg()}"
|
||||
android:onClick="@{(v)->viewModel.sendTxtMsg(v)}"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/ic_send_msg"
|
||||
android:visibility="@{viewModel.showSendBtn? View.VISIBLE:View.GONE}" />
|
||||
@ -181,9 +182,9 @@
|
||||
<RelativeLayout
|
||||
android:id="@+id/rlPhoto"
|
||||
android:layout_width="0dp"
|
||||
android:onClick="@{()->viewModel.showChoosePic()}"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
android:layout_weight="1"
|
||||
android:onClick="@{()->viewModel.showChoosePic()}">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivPhoto"
|
||||
@ -206,9 +207,9 @@
|
||||
<RelativeLayout
|
||||
android:id="@+id/rlVideo"
|
||||
android:layout_width="0dp"
|
||||
android:onClick="@{()->viewModel.showChooseVideo()}"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
android:layout_weight="1"
|
||||
android:onClick="@{()->viewModel.showChooseVideo()}">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivVideo"
|
||||
@ -232,8 +233,8 @@
|
||||
android:id="@+id/rlFile"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:onClick="@{()->viewModel.showChooseFile()}"
|
||||
android:layout_weight="1">
|
||||
android:layout_weight="1"
|
||||
android:onClick="@{()->viewModel.showChooseFile()}">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivFile"
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="mainModel"
|
||||
type="com.tenlionsoft.aimz_k.viewmodel.MainPageViewModel" />
|
||||
</data>
|
||||
|
||||
<RelativeLayout
|
||||
|
@ -8,6 +8,10 @@
|
||||
name="pos"
|
||||
type="Integer" />
|
||||
|
||||
<variable
|
||||
name="size"
|
||||
type="Integer" />
|
||||
|
||||
<import type="android.view.View" />
|
||||
|
||||
<variable
|
||||
@ -96,6 +100,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:visibility="@{pos< size?View.VISIBLE:View.GONE}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="10dp"
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -12,7 +12,7 @@
|
||||
type="com.tenlionsoft.aimz_k.model.MsgBean" />
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -13,7 +13,7 @@
|
||||
type="com.tenlionsoft.aimz_k.model.MsgBean" />
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -13,7 +13,7 @@
|
||||
type="com.tenlionsoft.aimz_k.model.MsgBean" />
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />>
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />
|
||||
|
||||
<import type="com.tenlionsoft.aimz_k.widget.BindingUtils" />
|
||||
</data>
|
||||
|
@ -13,7 +13,7 @@
|
||||
type="com.tenlionsoft.aimz_k.model.MsgBean" />
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -14,7 +14,7 @@
|
||||
type="com.tenlionsoft.aimz_k.model.MsgBean" />
|
||||
<variable
|
||||
name="state"
|
||||
type="Integer" />
|
||||
type="String" />>
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -1,26 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout
|
||||
<RelativeLayout
|
||||
android:id="@+id/ll_search_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/shp_white_5_radius"
|
||||
android:gravity="center"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/ic_search_gray" />
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_load"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="8dp">
|
||||
|
||||
<TextView
|
||||
<ImageView
|
||||
android:id="@+id/iv_socket_status"
|
||||
android:layout_width="5dp"
|
||||
android:layout_height="5dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginRight="3dp"
|
||||
android:src="@drawable/shp_circle_red" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_socket_loading"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_socket_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="登陆中..."
|
||||
android:textColor="@color/gray_6f"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:gravity="center"
|
||||
android:text="搜索"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/ic_search_gray" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:gravity="center"
|
||||
android:text="搜索"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</layout>
|
@ -3,7 +3,7 @@ package com.tenlionsoft.baselib.contacts
|
||||
object NetConfig {
|
||||
const val BASE_URL = "http://192.168.0.26:8888/"
|
||||
|
||||
const val WS_URL = "wss://192.168.0.0:8089/wsscoket";//Socket连接地址
|
||||
const val WS_URL = "ws://192.168.0.26:1991/";//Socket连接地址
|
||||
|
||||
const val MAIN_URL = BASE_URL + "system/"
|
||||
|
||||
|
@ -5,6 +5,7 @@ package com.tenlionsoft.baselib.contacts
|
||||
*/
|
||||
object ProjectConfig {
|
||||
|
||||
|
||||
const val IS_SECRET = false;
|
||||
const val SECRET: String = "CMXX_TOKEN_INFOS"; //秘钥
|
||||
const val SOCKET_MSG_SECRET: String = "SocKEtsEcReT_KeY"; //消息秘钥
|
||||
@ -15,6 +16,15 @@ object ProjectConfig {
|
||||
const val APP_DOWNLOAD_URL: String =
|
||||
NetConfig.MAIN_URL + "app/appversion/download/" + APP_VERSION_ID
|
||||
|
||||
//消息类型
|
||||
const val MSG_TEXT = "MSG_TEXT"
|
||||
const val MSG_FILE = "MSG_FILE"
|
||||
const val MSG_IMG = "MSG_IMG"
|
||||
const val MSG_VIDEO = "MSG_VIDEO"
|
||||
const val MSG_STATUS = "STATUS" //状态消息
|
||||
const val MSG_SEND_ING: String = "PENDING"//11 //发送中
|
||||
const val MSG_SEND_FAIL: String = "ERROR"//12 //发送失败
|
||||
const val MSG_SEND_SUCCESS: String = "SUCCESS_SEND"////发送成功
|
||||
|
||||
|
||||
/********Action********/
|
||||
@ -23,4 +33,11 @@ object ProjectConfig {
|
||||
const val ACTION_UPDATE_SUCCESS: String = "com.tenlion.soft.aimz_k.update_success"
|
||||
const val ACTION_UPDATE_START: String = "com.tenlion.soft.aimz_k.update_start"
|
||||
|
||||
/********socket*********/
|
||||
const val A_S_CONNECTED: String = "com.tenlion.soft.aimz_k.socket.connected" //连接socket
|
||||
const val A_S_FAIL: String = "com.tenlion.soft.aimz_k.socket.fail"//socket连接失败
|
||||
const val A_S_DISCONNECT: String = "com.tenlion.soft.aimz_k.socket.disconnect"//连接断开
|
||||
const val A_S_MSG_RECEIVER: String = "com.tenlion.soft.aimz_k.socket.receiver" //接收到信息
|
||||
const val A_S_MSG_SEND: String = "com.tenlion.soft.aimz_k.socket.send"//发送信息
|
||||
|
||||
}
|
@ -18,9 +18,13 @@ class BaseUrlInterceptor : Interceptor {
|
||||
val builder = request.newBuilder();
|
||||
val oldHttpUrl = request.url;
|
||||
val headers = request.headers("project");
|
||||
//公共header
|
||||
builder.addHeader("X-WG-TOKEN", SpUtils.getToken())
|
||||
builder.addHeader("X-WG-TYPE", "APP")
|
||||
//公共Token header
|
||||
if (headers.indexOf("token") != -1) {
|
||||
builder.removeHeader("token")
|
||||
builder.addHeader("X-WG-TOKEN", SpUtils.getToken())
|
||||
builder.addHeader("X-WG-TYPE", "APP")
|
||||
}
|
||||
|
||||
if (headers.isNotEmpty()) {
|
||||
builder.removeHeader("project");
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.tenlionsoft.baselib.utils
|
||||
|
||||
object TimeUtils {
|
||||
fun getNowDateMillis(): Long {
|
||||
return System.currentTimeMillis()
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:clickable="true"
|
||||
android:textColor="@color/white"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="18sp"
|
||||
tools:text="加载数据失败" />
|
||||
|
||||
|
@ -4,8 +4,10 @@
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="theme_bg_color">#F5F5F5</color>
|
||||
<color name="tr">#00FFFFFF</color>
|
||||
<color name="tr_bg">#54000000</color>
|
||||
<color name="tr_bg">#A3FFFFFF</color>
|
||||
<color name="chat_page_bg">#EDEDED</color>
|
||||
<color name="red">#E75D58</color>
|
||||
<color name="green">#45F68B</color>
|
||||
<color name="gray_6f">#6F6E6E</color>
|
||||
<color name="black">#000000</color>
|
||||
</resources>
|
Loading…
Reference in New Issue
Block a user