消息状态
This commit is contained in:
parent
ae61b72fc3
commit
9a4e454ac5
@ -30,7 +30,7 @@
|
||||
<activity
|
||||
android:name=".page.activity.ChatActivity"
|
||||
android:exported="false"
|
||||
android:windowSoftInputMode="adjustPan|stateHidden" />
|
||||
android:windowSoftInputMode="adjustPan|stateAlwaysHidden" />
|
||||
<activity
|
||||
android:name=".page.activity.SplashActivity"
|
||||
android:exported="true"
|
||||
|
@ -3,6 +3,7 @@ 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.MsgCategoryBean
|
||||
import com.tenlionsoft.aimz_k.model.MsgConvertBean
|
||||
import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
@ -65,4 +66,20 @@ object ConvertBeanUtils {
|
||||
)
|
||||
}
|
||||
|
||||
fun convertCategoryBean(msgBean: MsgBean): MsgCategoryBean {
|
||||
return MsgCategoryBean(
|
||||
avatar = "",
|
||||
messageType = msgBean.messageType,
|
||||
messageId = msgBean.messageId,
|
||||
receiverType = msgBean.receiverType,
|
||||
receiverId = msgBean.receiverId,
|
||||
senderType = msgBean.senderType,
|
||||
senderId = msgBean.senderId,
|
||||
status = msgBean.status,
|
||||
timestamp = msgBean.timestamp,
|
||||
msgType = msgBean.msgType,
|
||||
body = msgBean.body
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -22,10 +22,14 @@ class ChatMsgAdapter(datas: List<MsgBean>, viewModel: ChatPageViewModel) :
|
||||
override fun getItemBinding(parent: ViewGroup, viewType: Int): ViewDataBinding {
|
||||
when (viewType) {
|
||||
MsgTypeStateEnum.MSG_TO_OTHER_TXT -> {
|
||||
return ItemMsgMyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return ItemMsgOtherBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}//发送文本
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_TXT -> {
|
||||
return ItemMsgOtherBinding.inflate(
|
||||
return ItemMsgMyBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
@ -86,46 +90,55 @@ class ChatMsgAdapter(datas: List<MsgBean>, viewModel: ChatPageViewModel) :
|
||||
override fun bindItem(holder: BaseViewHolder<ViewDataBinding>, position: Int) {
|
||||
val itemType = getItemViewType(position)
|
||||
when (itemType) {
|
||||
//发送文本
|
||||
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].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].status
|
||||
}//收到文本信息
|
||||
}
|
||||
//收到文本信息
|
||||
MsgTypeStateEnum.MSG_FROM_OTHER_TXT -> {
|
||||
(holder.binding as ItemMsgMyBinding).pos = position
|
||||
(holder.binding as ItemMsgMyBinding).bean = list[position]
|
||||
(holder.binding as ItemMsgMyBinding).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].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].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].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].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].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].status
|
||||
}//语音
|
||||
}
|
||||
|
||||
else -> {
|
||||
throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ data class MsgCategoryBean(
|
||||
@ColumnInfo(name = "messageId")
|
||||
var messageId: String?, //消息ID
|
||||
@ColumnInfo(name = "messageType")
|
||||
var messageType: String, //消息类型
|
||||
var messageType: String?, //消息类型
|
||||
@ColumnInfo(name = "receiverId")
|
||||
var receiverId: String?, //接受人ID
|
||||
@ColumnInfo(name = "receiverType")
|
||||
|
@ -4,6 +4,7 @@ import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.tenlionsoft.aimz_k.ConvertBeanUtils
|
||||
|
||||
@Dao
|
||||
interface MsgCategoryDao {
|
||||
@ -14,13 +15,13 @@ interface MsgCategoryDao {
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_category")
|
||||
fun getAllCategory(): List<MsgCategoryBean>
|
||||
suspend fun getAllCategory(): List<MsgCategoryBean?>
|
||||
|
||||
/**
|
||||
* 根据发送人ID获取
|
||||
*/
|
||||
@Query("SELECT * FROM db_category WHERE senderId=:senderId")
|
||||
fun getCategoryBySenderId(senderId: String): MsgCategoryBean?
|
||||
suspend fun getCategoryBySenderId(senderId: String): MsgCategoryBean?
|
||||
|
||||
/**
|
||||
* 根据ID获取消息
|
||||
@ -29,7 +30,7 @@ interface MsgCategoryDao {
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_category WHERE id =(:id) ")
|
||||
fun getCategoryById(id: String): List<MsgCategoryBean>
|
||||
suspend fun getCategoryById(id: String): List<MsgCategoryBean>
|
||||
|
||||
/**
|
||||
* 根据信息来源查询消息
|
||||
@ -38,14 +39,14 @@ interface MsgCategoryDao {
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * FROM db_category WHERE `senderId`=(:from)")
|
||||
fun getCategoryByFrom(from: String?): List<MsgCategoryBean>
|
||||
suspend fun getCategoryByFrom(from: String?): List<MsgCategoryBean>
|
||||
|
||||
|
||||
/**
|
||||
* 查询与单人的聊天记录 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)
|
||||
*/
|
||||
@Query("SELECT * FROM db_category t1 ORDER by t1.timestamp ASC LIMIT (((:page)-1)*(:pageSize)),(:pageSize)")
|
||||
fun getCategoryPage(
|
||||
suspend fun getCategoryPage(
|
||||
pageSize: Int,
|
||||
page: Int
|
||||
): MutableList<MsgCategoryBean>
|
||||
@ -55,7 +56,7 @@ interface MsgCategoryDao {
|
||||
* 清空与某个人的聊天记录
|
||||
*/
|
||||
@Query("DELETE FROM db_category WHERE `senderId`=(:from) AND receiverId=(:to) OR `senderId`=(:to) AND receiverId=(:from)")
|
||||
fun delChatHistory(from: String?, to: String?)
|
||||
suspend fun delChatHistory(from: String?, to: String?)
|
||||
|
||||
/**
|
||||
* 添加消息多个
|
||||
@ -63,13 +64,13 @@ interface MsgCategoryDao {
|
||||
* @param beans
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertAll(vararg beans: MsgCategoryBean)
|
||||
suspend fun insertAll(vararg beans: MsgCategoryBean)
|
||||
|
||||
/**
|
||||
* 批量添加
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertAll(beans: List<MsgCategoryBean>)
|
||||
suspend fun insertAll(beans: List<MsgCategoryBean>)
|
||||
|
||||
|
||||
/**
|
||||
@ -78,23 +79,35 @@ interface MsgCategoryDao {
|
||||
* @param bean
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertMsg(bean: MsgCategoryBean)
|
||||
suspend fun insertMsg(bean: MsgCategoryBean)
|
||||
|
||||
/**
|
||||
* 清除全部聊天记录
|
||||
*/
|
||||
@Query("DELETE FROM db_category")
|
||||
fun delAllMsg()
|
||||
suspend fun delAllMsg()
|
||||
|
||||
/**
|
||||
* 根据发送人的ID插入或者更新
|
||||
*/
|
||||
fun updateOrInsert(senderId: String, msgBean: MsgBean)
|
||||
suspend fun updateOrInsert(senderId: String, msgBean: MsgBean) {
|
||||
val bean = getCategoryBySenderId(senderId)
|
||||
if (bean == null) {
|
||||
//需要转换成MsgCategoryBean
|
||||
insertMsg(ConvertBeanUtils.convertCategoryBean(msgBean))
|
||||
} else {
|
||||
updateCategory(senderId, msgBean.status, msgBean.body!!, msgBean.timestamp!!)
|
||||
}
|
||||
}
|
||||
|
||||
//更新
|
||||
@Query("UPDATE db_category SET status=:status WHERE senderId=:senderId")
|
||||
suspend fun updateStatus(senderId: String, status: String)
|
||||
|
||||
/**
|
||||
* 更新 消息体 时间戳 状态
|
||||
* @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)
|
||||
suspend fun updateCategory(senderId: String, status: String?, body: String, time: Long)
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
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!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -111,7 +111,7 @@ interface MsgDao {
|
||||
* @param bean
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertMsg(bean: MsgBean)
|
||||
suspend fun insertMsg(bean: MsgBean)
|
||||
|
||||
/**
|
||||
* 清除全部聊天记录
|
||||
|
@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.atwa.filepicker.core.FilePicker
|
||||
import com.tenlionsoft.aimz_k.R
|
||||
import com.tenlionsoft.aimz_k.databinding.ActivityChatBinding
|
||||
@ -19,6 +20,7 @@ import com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel
|
||||
import com.tenlionsoft.baselib.base.BaseActivity
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.utils.SpUtils
|
||||
import com.tenlionsoft.baselib.widget.SoftKeyBoardListener
|
||||
import com.tenlionsoft.baselib.widget.wheel.WheelView
|
||||
|
||||
/**
|
||||
@ -26,23 +28,33 @@ import com.tenlionsoft.baselib.widget.wheel.WheelView
|
||||
*/
|
||||
class ChatActivity : BaseActivity() {
|
||||
private lateinit var mBinding: ActivityChatBinding
|
||||
|
||||
private lateinit var mLocalReceiver: LocalReceiver
|
||||
var chatPageViewModel: ChatPageViewModel? = null
|
||||
private val filePicker = FilePicker.getInstance(this)
|
||||
|
||||
|
||||
override fun bindView() {
|
||||
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_chat);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
window.statusBarColor =
|
||||
ContextCompat.getColor(this, com.tenlionsoft.baselib.R.color.chat_page_bg)
|
||||
val fromId = intent.getStringExtra("fromId")
|
||||
|
||||
val fromId = intent.getStringExtra("fromId") //传递过来的接收人
|
||||
val name = intent.getStringExtra("name")
|
||||
if (name.isNullOrEmpty()) {
|
||||
mBinding.tvTitle.text = "临时客户"
|
||||
}
|
||||
|
||||
chatPageViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ChatPageViewModel(fromId!!, SpUtils.getId()) as T
|
||||
return ChatPageViewModel(
|
||||
fromId!!,
|
||||
SpUtils.getId(),
|
||||
this@ChatActivity.applicationContext
|
||||
) as T
|
||||
}
|
||||
})[ChatPageViewModel::class.java]
|
||||
|
||||
|
||||
mBinding.ivBack.setOnClickListener { finish(); }
|
||||
mBinding.srlChats.setEnableRefresh(false)
|
||||
mBinding.srlChats.setEnableLoadMore(false)
|
||||
@ -53,17 +65,21 @@ class ChatActivity : BaseActivity() {
|
||||
mBinding.etMsg.append(it.emoji)
|
||||
}
|
||||
//显示/隐藏软键盘
|
||||
chatPageViewModel!!.showSoftKeyboard.observe(this) {
|
||||
if (it) {
|
||||
showSoftKeyBoard(mBinding.etMsg)
|
||||
chatPageViewModel!!.showChooseLayout.value = false
|
||||
chatPageViewModel!!.showEmojiLayout.value = false
|
||||
chatPageViewModel!!.showReplyLayout.value = false
|
||||
} else {
|
||||
hideSoftKeyboard()
|
||||
}
|
||||
}
|
||||
// chatPageViewModel!!.showSoftKeyboard.observe(this) {
|
||||
// if (it) {
|
||||
// showSoftKeyBoard(mBinding.etMsg)
|
||||
// chatPageViewModel!!.showChooseLayout.value = false
|
||||
// chatPageViewModel!!.showEmojiLayout.value = false
|
||||
// chatPageViewModel!!.showReplyLayout.value = false
|
||||
// val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager
|
||||
// val itemCount = layoutManager.itemCount
|
||||
// mBinding.rlvChats.smoothScrollToPosition(itemCount - 1)
|
||||
// } else {
|
||||
// hideSoftKeyboard()
|
||||
// }
|
||||
// }
|
||||
mBinding.rlContent.setOnClickListener {
|
||||
Log.e("ChatActivity", "bindView: 点击")
|
||||
chatPageViewModel!!.showChooseLayout.value = false
|
||||
chatPageViewModel!!.showEmojiLayout.value = false
|
||||
chatPageViewModel!!.showReplyLayout.value = false
|
||||
@ -107,10 +123,18 @@ class ChatActivity : BaseActivity() {
|
||||
}
|
||||
chatPageViewModel!!.scrollListToBottom.observe(this) {
|
||||
if (it) {
|
||||
mBinding.rlvChats.scrollToPosition(chatPageViewModel!!.adapter.list.size - 1)//滚动到底部
|
||||
Log.e("ChatActivity", "bindView: ${Thread.currentThread().name}")
|
||||
val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager
|
||||
val itemCount = layoutManager.itemCount
|
||||
mBinding.rlvChats.scrollToPosition(itemCount - 1)//滚动到底部
|
||||
chatPageViewModel!!.scrollListToBottom.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SoftKeyBoardListener().setChangeListener(this@ChatActivity,
|
||||
{ _ -> Log.e("ChatActivity", "bindView: 显示") },
|
||||
{ _ -> Log.e("ChatActivity", "bindView: 隐藏") })
|
||||
registerLocalReceiver()
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ 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
|
||||
@ -132,6 +131,7 @@ class MainActivity : BaseActivity() {
|
||||
filter.addAction(ProjectConfig.A_S_CONNECTED)//socket连接成功
|
||||
filter.addAction(ProjectConfig.A_S_FAIL)//socket连接失败
|
||||
filter.addAction(ProjectConfig.A_S_DISCONNECT)//socket连接断开
|
||||
filter.addAction(ProjectConfig.A_S_MSG_RECEIVER)//监听消息收到
|
||||
registerReceiver(mLocalReceiver, filter)
|
||||
}
|
||||
|
||||
@ -189,39 +189,46 @@ class MainActivity : BaseActivity() {
|
||||
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()
|
||||
}//开始下载
|
||||
}
|
||||
//更新进度
|
||||
ProjectConfig.ACTION_UPDATE_PROGRESS -> {
|
||||
val progress = intent.getIntExtra("progress", 0)
|
||||
LogUtils.e("当前进度:$progress")
|
||||
mUpdateView?.setCurrentProgress(progress)
|
||||
}//更新进度
|
||||
}
|
||||
//下载失败
|
||||
ProjectConfig.ACTION_UPDATE_ERROR -> {
|
||||
//下载失败
|
||||
mUpdateView?.dismiss()
|
||||
}//下载失败
|
||||
}
|
||||
//下载成功
|
||||
ProjectConfig.ACTION_UPDATE_SUCCESS -> {
|
||||
//下载成功
|
||||
mUpdateView?.dismiss()
|
||||
//判断是否可以安装
|
||||
val apkFile = intent.getSerializableExtra("apkFile") as File?
|
||||
installApk(apkFile!!)
|
||||
}//下载成功
|
||||
}
|
||||
//socket 连接成功
|
||||
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)
|
||||
val extra = intent.getStringExtra("msg")
|
||||
if (!extra.isNullOrEmpty()) {
|
||||
onSocketConnectListener?.onReceiverMsg(extra)
|
||||
}
|
||||
}//接收到信息
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package com.tenlionsoft.aimz_k.page.fragments
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -72,12 +71,9 @@ class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener,
|
||||
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
|
||||
}
|
||||
@ -99,17 +95,25 @@ class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener,
|
||||
mActivity?.startService(Intent(mActivity!!, SocketService::class.java))
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* 条目点击
|
||||
*/
|
||||
override fun onItemClick(msgCategoryBean: MsgCategoryBean) {
|
||||
Log.e("MsgFragment", "onItemClick: ${msgCategoryBean}")
|
||||
startActivity(Intent(mActivity, ChatActivity::class.java))
|
||||
startActivity(
|
||||
Intent(mActivity, ChatActivity::class.java).putExtra(
|
||||
"fromId",
|
||||
msgCategoryBean.senderId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
//监听socket连接状态
|
||||
override fun onListener(status: String) {
|
||||
Log.e("MsgFragment", "onListener: ${status}")
|
||||
when (status) {
|
||||
ProjectConfig.A_S_CONNECTED -> {
|
||||
viewModel.isLogining.value = false
|
||||
@ -124,7 +128,7 @@ class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener,
|
||||
//接收到socket信息
|
||||
override fun onReceiverMsg(msg: String) {
|
||||
if (msg.isNotEmpty()) {
|
||||
viewModel.fromMsg(msg)
|
||||
viewModel.fromMsg(msg, mActivity!!.applicationContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.tenlionsoft.aimz_k.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
@ -27,7 +28,11 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ChatPageViewModel(private val fromId: String, private val toId: String) : BaseViewModel() {
|
||||
class ChatPageViewModel(
|
||||
private val fromId: String,
|
||||
private val toId: String,
|
||||
private val context: Context
|
||||
) : BaseViewModel() {
|
||||
val txtMsg = MutableLiveData<String>("")
|
||||
val showSendBtn = MutableLiveData(false)//显示/隐藏发送按钮
|
||||
val showEmojiLayout = MutableLiveData(false)//显示/隐藏emoji
|
||||
@ -43,9 +48,11 @@ class ChatPageViewModel(private val fromId: String, private val toId: String) :
|
||||
Log.e("ChatPageViewModel", "Init: ${showSendBtn.value}")
|
||||
viewModelScope.launch {
|
||||
val list = getList()
|
||||
Log.e("ChatPageViewModel", "Init:${list} ")
|
||||
_msgList.value = list
|
||||
adapter.setData(list)
|
||||
scrollListToBottom.value = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//获取列表
|
||||
@ -58,19 +65,14 @@ class ChatPageViewModel(private val fromId: String, private val toId: String) :
|
||||
|
||||
fun onTxtChange(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
this.txtMsg.value = s.toString()
|
||||
|
||||
showSendBtn.value = s.isNotEmpty()
|
||||
Log.e("ChatPageViewModel", "onTxtChange: ${showSendBtn.value}")
|
||||
}
|
||||
|
||||
fun onShowReplyLayout() {
|
||||
Log.e("ChatPageViewModel", "onShowReplyLayout切换前: ${showReplyLayout.value}")
|
||||
showReplyLayout.value = !showReplyLayout.value!!
|
||||
Log.e("ChatPageViewModel", "onShowReplyLayout切换后: ${showReplyLayout.value}")
|
||||
showEmojiLayout.value = false
|
||||
showChooseLayout.value = false
|
||||
showSoftKeyboard.value = !showReplyLayout.value!!
|
||||
Log.e("ChatPageViewModel", "onShowReplyLayout: ${showSoftKeyboard.value}")
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,51 +138,71 @@ class ChatPageViewModel(private val fromId: String, private val toId: String) :
|
||||
|
||||
}
|
||||
|
||||
//刷新
|
||||
private fun refresh() {
|
||||
viewModelScope.launch {
|
||||
val list = getList()
|
||||
_msgList.value = list
|
||||
adapter.setData(_msgList.value!!)
|
||||
}
|
||||
}
|
||||
|
||||
//刷新页面
|
||||
private fun addBeanToView(msgBean: MsgBean) {
|
||||
_msgList.value = _msgList.value?.plus(msgBean)
|
||||
adapter.setData(_msgList.value!!)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送文本信息
|
||||
*/
|
||||
fun sendTxtMsg(v: View) {
|
||||
if (txtMsg.value!!.isNotEmpty()) {
|
||||
val intent = Intent(ProjectConfig.A_S_MSG_SEND)
|
||||
val b = buildSendBean()
|
||||
|
||||
val b = buildSendBean(ProjectConfig.MSG_TEXT)
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val dao = DbManager.db.msgDao()
|
||||
val msgBean = ConvertBeanUtils.convertBeanToMsgBean(b)
|
||||
dao.insertMsg(msgBean)
|
||||
val msgBean = insertMsgBeanToDb(b)
|
||||
_msgList.value = _msgList.value?.plus(msgBean)
|
||||
adapter.setData(_msgList.value!!)
|
||||
}
|
||||
}
|
||||
Log.e("ChatPageViewModel", "sendTxtMsg: ${b}")
|
||||
intent.putExtra("msgBean", b)
|
||||
v.context.sendBroadcast(intent)
|
||||
txtMsg.value = ""
|
||||
scrollListToBottom.value = true
|
||||
}
|
||||
}
|
||||
|
||||
//TODO 刷新列表
|
||||
private suspend fun insertMsgBeanToDb(b: MsgConvertBean): MsgBean {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val dao = DbManager.db.msgDao()
|
||||
val cDao = DbManager.db.categoryDao()
|
||||
val msgBean = ConvertBeanUtils.convertBeanToMsgBean(b)
|
||||
cDao.updateCategory(b.receiver.receiverId!!, b.status, b.body, b.timestamp)
|
||||
dao.insertMsg(msgBean)
|
||||
return@withContext msgBean
|
||||
}
|
||||
}
|
||||
|
||||
//收到消息
|
||||
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,
|
||||
val cDao = DbManager.db.categoryDao()
|
||||
val statusType =
|
||||
mGson.fromJson(bean.data.body, BodyContent::class.java).statusType!!
|
||||
)
|
||||
dao.updateStatus(bean.data.messageId, statusType)
|
||||
cDao.updateStatus(bean.data.sender.senderId!!, statusType)
|
||||
}
|
||||
//TODO 刷新列表
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
//消息
|
||||
//新消息
|
||||
is CoverSealedBean.Msg -> {
|
||||
//插入信息表
|
||||
//并更新category表
|
||||
@ -191,24 +213,32 @@ class ChatPageViewModel(private val fromId: String, private val toId: String) :
|
||||
msgDao.insertMsg(bean.msgBean)
|
||||
cDao.updateOrInsert(bean.msgBean.senderId!!, bean.msgBean)
|
||||
}
|
||||
addBeanToView(bean.msgBean)
|
||||
sendStatusMsg(bean.msgBean.messageId!!)
|
||||
}
|
||||
//刷新列表
|
||||
scrollListToBottom.value = true
|
||||
Log.e("ChatPageViewModel", "receiveMsg接收到消息: ${bean.msgBean}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendStatusMsg(msgId: String) {
|
||||
val b = buildStatusBean(msgId)
|
||||
val intent = Intent(ProjectConfig.A_S_MSG_SEND)
|
||||
intent.putExtra("msgBean", b)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
private fun buildSendBean(): MsgConvertBean {
|
||||
//构建发送实体
|
||||
private fun buildSendBean(type: String): MsgConvertBean {
|
||||
val bodyBean = BodyContent(content = txtMsg.value, null, null)
|
||||
var body = mGson.toJson(bodyBean)
|
||||
val body = mGson.toJson(bodyBean)
|
||||
return MsgConvertBean(
|
||||
body = body,
|
||||
customMessageType = "",
|
||||
messageId = TimeUtils.getNowDateMillis().toString(),
|
||||
messageType = ProjectConfig.MSG_TEXT,
|
||||
messageType = type,
|
||||
metadata = "",
|
||||
timestamp = TimeUtils.getNowDateMillis(),
|
||||
sender = Sender(
|
||||
@ -216,10 +246,33 @@ class ChatPageViewModel(private val fromId: String, private val toId: String) :
|
||||
senderType = ""
|
||||
),
|
||||
receiver = Receiver(
|
||||
receiverId = "2",
|
||||
receiverId = fromId,
|
||||
receiverType = "SINGLE_USER"
|
||||
),
|
||||
status = ProjectConfig.MSG_SEND_ING,
|
||||
)
|
||||
}
|
||||
|
||||
//构建状态信息
|
||||
private fun buildStatusBean(messageId: String): MsgConvertBean {
|
||||
val bodyBean = BodyContent(content = null, msg = "", statusType = "SUCCESS_RECEIVED")
|
||||
val body = mGson.toJson(bodyBean)
|
||||
return MsgConvertBean(
|
||||
body = body,
|
||||
customMessageType = "",
|
||||
messageId = messageId,
|
||||
messageType = ProjectConfig.MSG_STATUS,
|
||||
metadata = "",
|
||||
timestamp = TimeUtils.getNowDateMillis(),
|
||||
sender = Sender(
|
||||
senderId = SpUtils.getId(),
|
||||
senderType = ""
|
||||
),
|
||||
receiver = Receiver(
|
||||
receiverId = fromId,
|
||||
receiverType = "SINGLE_USER"
|
||||
),
|
||||
status = "",
|
||||
)
|
||||
}
|
||||
}
|
@ -1,13 +1,24 @@
|
||||
package com.tenlionsoft.aimz_k.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.gson.Gson
|
||||
import com.tenlionsoft.aimz_k.ConvertBeanUtils
|
||||
import com.tenlionsoft.aimz_k.adapter.CategoryAdapter
|
||||
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.MsgCategoryBean
|
||||
import com.tenlionsoft.aimz_k.model.MsgConvertBean
|
||||
import com.tenlionsoft.aimz_k.model.Receiver
|
||||
import com.tenlionsoft.aimz_k.model.Sender
|
||||
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
|
||||
@ -16,14 +27,11 @@ class MsgViewModel : ViewModel() {
|
||||
private val _pwdList = MutableLiveData<List<MsgCategoryBean>>()
|
||||
var adapter: CategoryAdapter = CategoryAdapter(_pwdList.value ?: emptyList(), this)
|
||||
var onItemClickListener: OnItemClickListener? = null
|
||||
val isLogining = MutableLiveData<Boolean>(false)
|
||||
val isLogining = MutableLiveData(false)
|
||||
private val mGson = Gson()
|
||||
private var mCurrentPage: Int = 1
|
||||
var isHasMore: MutableLiveData<Boolean> = MutableLiveData<Boolean>(false)
|
||||
|
||||
init {
|
||||
getList(true)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
@ -72,12 +80,74 @@ class MsgViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
//接收到信息
|
||||
fun fromMsg(msg: String) {
|
||||
fun fromMsg(msg: String, context: Context) {
|
||||
Log.e("MsgViewModel", "fromMsg: ${msg}")
|
||||
if (msg.isNotEmpty()) {
|
||||
val bean = ConvertBeanUtils.covertBean(msg)
|
||||
when (bean) {
|
||||
is CoverSealedBean.StateBean -> {}//消息状态
|
||||
is CoverSealedBean.Msg -> {}//消息
|
||||
//状态消息
|
||||
is CoverSealedBean.StateBean -> {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val dao = DbManager.db.msgDao()
|
||||
val cDao = DbManager.db.categoryDao()
|
||||
val statusType =
|
||||
mGson.fromJson(bean.data.body, BodyContent::class.java).statusType!!
|
||||
dao.updateStatus(bean.data.messageId, statusType)
|
||||
cDao.updateStatus(bean.data.sender.senderId!!, statusType)
|
||||
}
|
||||
//刷新
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
//消息
|
||||
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)
|
||||
}
|
||||
sendStatusMsg(bean.msgBean.messageId!!, bean.msgBean.senderId!!, context)
|
||||
//刷新列表
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendStatusMsg(msgId: String, fromId: String, context: Context) {
|
||||
val b = buildStatusBean(msgId, fromId)
|
||||
val intent = Intent(ProjectConfig.A_S_MSG_SEND)
|
||||
intent.putExtra("msgBean", b)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
//构建状态信息
|
||||
private fun buildStatusBean(messageId: String, fromId: String): MsgConvertBean {
|
||||
val bodyBean = BodyContent(content = null, msg = "", statusType = "SUCCESS_RECEIVED")
|
||||
val body = mGson.toJson(bodyBean)
|
||||
return MsgConvertBean(
|
||||
body = body,
|
||||
customMessageType = "",
|
||||
messageId = messageId,
|
||||
messageType = ProjectConfig.MSG_STATUS,
|
||||
metadata = "",
|
||||
timestamp = TimeUtils.getNowDateMillis(),
|
||||
sender = Sender(
|
||||
senderId = SpUtils.getId(),
|
||||
senderType = ""
|
||||
),
|
||||
receiver = Receiver(
|
||||
receiverId = fromId,
|
||||
receiverType = "SINGLE_USER"
|
||||
),
|
||||
status = "",
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,7 @@ package com.tenlionsoft.aimz_k.widget
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.BindingAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -9,16 +10,20 @@ import androidx.recyclerview.widget.RecyclerView.Adapter
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.google.gson.Gson
|
||||
import com.tenlionsoft.aimz_k.R
|
||||
import com.tenlionsoft.aimz_k.model.BodyContent
|
||||
import com.tenlionsoft.baselib.contacts.ProjectConfig
|
||||
import com.tenlionsoft.baselib.utils.TimeUtils
|
||||
|
||||
|
||||
object BindingUtils {
|
||||
|
||||
@BindingAdapter("setAdapter")
|
||||
@BindingAdapter("setLinearLayoutAdapter")
|
||||
@JvmStatic
|
||||
fun bindAdapterToRecyclerView(recyclerView: RecyclerView, adapter: Adapter<*>) {
|
||||
recyclerView.layoutManager = LinearLayoutManager(recyclerView.context)
|
||||
val linearLayoutManager = LinearLayoutManager(recyclerView.context)
|
||||
recyclerView.layoutManager = linearLayoutManager
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@ -48,11 +53,35 @@ object BindingUtils {
|
||||
imageView.setImageResource(url)
|
||||
}
|
||||
|
||||
@BindingAdapter("jsonConvertMsgBody")
|
||||
@JvmStatic
|
||||
fun jsonConvert(tv: TextView, str: String?) {
|
||||
if (str.isNullOrEmpty()) {
|
||||
tv.text = ""
|
||||
} else {
|
||||
val gson = Gson()
|
||||
val body = gson.fromJson(str, BodyContent::class.java)
|
||||
tv.text = body.content
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("millConvertDate")
|
||||
@JvmStatic
|
||||
fun millConvertDate(tv: TextView, long: Long?) {
|
||||
if (long == null) {
|
||||
tv.text = ""
|
||||
} else {
|
||||
tv.text = TimeUtils.millis2HMStr(long)
|
||||
}
|
||||
}
|
||||
|
||||
//发送中
|
||||
@BindingAdapter("isShowLoading")
|
||||
@JvmStatic
|
||||
fun sending(view: View, status: String) {
|
||||
fun sending(view: View, status: String?) {
|
||||
if (status.isNullOrEmpty()) {
|
||||
view.visibility = View.GONE
|
||||
} else {
|
||||
when (status) {
|
||||
ProjectConfig.MSG_SEND_SUCCESS -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_FAIL -> view.visibility = View.GONE
|
||||
@ -60,16 +89,22 @@ object BindingUtils {
|
||||
else -> view.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//发送失败
|
||||
@BindingAdapter("isShowFail")
|
||||
@JvmStatic
|
||||
fun sendFail(view: View, status: String) {
|
||||
fun sendFail(view: View, status: String?) {
|
||||
if (status.isNullOrEmpty()) {
|
||||
view.visibility = View.GONE
|
||||
} else {
|
||||
when (status) {
|
||||
ProjectConfig.MSG_SEND_SUCCESS -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_FAIL -> view.visibility = View.GONE
|
||||
ProjectConfig.MSG_SEND_ING -> view.visibility = View.VISIBLE
|
||||
ProjectConfig.MSG_SEND_FAIL -> view.visibility = View.VISIBLE
|
||||
ProjectConfig.MSG_SEND_ING -> view.visibility = View.GONE
|
||||
else -> view.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@
|
||||
android:src="@drawable/ic_back_left" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
@ -73,12 +74,17 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rlv_chats"
|
||||
setAdapter="@{viewModel.adapter}"
|
||||
setLinearLayoutAdapter="@{viewModel.adapter}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/item_msg_my" />
|
||||
</RelativeLayout>
|
||||
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -119,6 +125,8 @@
|
||||
android:background="@drawable/shp_white_5_radius"
|
||||
android:gravity="center_vertical"
|
||||
android:hint="请输入内容"
|
||||
android:maxLines="5"
|
||||
android:minLines="1"
|
||||
android:onTextChanged="@{viewModel::onTxtChange}"
|
||||
android:padding="10dp"
|
||||
android:text="@{viewModel.txtMsg}"
|
||||
|
@ -27,7 +27,7 @@
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rlv_msgs"
|
||||
android:layout_width="match_parent"
|
||||
setAdapter="@{msgViewModel.adapter}"
|
||||
setLinearLayoutAdapter="@{msgViewModel.adapter}"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/item_category" />
|
||||
|
||||
|
@ -37,13 +37,12 @@
|
||||
android:layout_centerInParent="true"
|
||||
android:scaleType="fitXY"
|
||||
tools:src="@drawable/app_logo_small" />
|
||||
|
||||
<!-- android:visibility="@{item.read?View.VISIBLE:View.GONE}"-->
|
||||
<ImageView
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/shp_circle_red"
|
||||
android:visibility="@{item.read?View.VISIBLE:View.GONE}" />
|
||||
android:src="@drawable/shp_circle_red" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
@ -74,38 +73,39 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@{item.fromName}"
|
||||
android:text="@{item.receiverType}"
|
||||
android:textColor="#1D1D1D"
|
||||
android:textSize="18sp"
|
||||
android:textSize="14sp"
|
||||
tools:text="测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试" />
|
||||
|
||||
<TextView
|
||||
jsonConvertMsgBody="@{item.body}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@{item.body}"
|
||||
android:textColor="#B7B7B7"
|
||||
android:textSize="14sp"
|
||||
tools:text="测试聊天内容" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
millConvertDate="@{item.timestamp}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{String.valueOf(item.id)}"
|
||||
android:textColor="#CACACA"
|
||||
android:textSize="14sp"
|
||||
android:textSize="12sp"
|
||||
tools:text="16:00" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:visibility="@{pos< size?View.VISIBLE:View.GONE}"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="#E6E6E6" />
|
||||
android:background="#E6E6E6"
|
||||
android:visibility="@{pos< size?View.VISIBLE:View.GONE}" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</layout>
|
@ -46,6 +46,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminateBehavior="repeat"
|
||||
isShowLoading="@{state}"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
|
||||
<ImageView
|
||||
@ -54,7 +55,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
isShowFail="@{state}"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
|
||||
@ -65,6 +66,7 @@
|
||||
android:background="@drawable/ic_message_text_send"
|
||||
android:gravity="center|left"
|
||||
android:maxWidth="200dp"
|
||||
jsonConvertMsgBody="@{bean.body}"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="10dp"
|
||||
android:textColor="@color/black"
|
||||
|
@ -43,6 +43,7 @@
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
isShowLoading="@{state}"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
|
||||
@ -52,7 +53,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
isShowFail="@{state}"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
isShowLoading="@{state}"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
|
||||
@ -52,8 +53,8 @@
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
isShowFail="@{state}"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
android:id="@+id/pb_sending"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
isShowLoading="@{state}"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
@ -51,9 +52,9 @@
|
||||
android:id="@+id/iv_msg_state_fail"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
isShowFail="@{state}"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="pos"
|
||||
type="Integer" />
|
||||
@ -34,6 +35,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_content"
|
||||
jsonConvertMsgBody="@{bean.body}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
@ -43,8 +45,7 @@
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="5dp"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="14sp"
|
||||
tools:text="测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试" />
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
@ -55,6 +56,7 @@
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_sending"
|
||||
isShowLoading="@{state}"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
@ -63,11 +65,11 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_msg_state_fail"
|
||||
isShowFail="@{state}"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
@ -65,6 +65,7 @@
|
||||
android:id="@+id/pb_sending"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
isShowLoading="@{state}"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
@ -74,8 +75,8 @@
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
isShowFail="@{state}"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
@ -73,6 +73,7 @@
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_centerInParent="true"
|
||||
isShowLoading="@{state}"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
|
||||
@ -80,9 +81,9 @@
|
||||
android:id="@+id/iv_msg_state_fail"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
isShowFail="@{state}"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/msg_state_fail_resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
@ -7,29 +7,44 @@
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/shp_white_5_radius"
|
||||
android:orientation="horizontal">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_search_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
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="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_load"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="8dp">
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="10dp">
|
||||
|
||||
<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_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:indeterminateBehavior="repeat"
|
||||
android:indeterminateDrawable="@drawable/anim_loading" />
|
||||
@ -42,27 +57,7 @@
|
||||
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_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" />
|
||||
android:textSize="10sp" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</layout>
|
@ -66,4 +66,5 @@ dependencies {
|
||||
api(libs.emojipicker)
|
||||
api(libs.xxpermissions)
|
||||
api(libs.filepicker)
|
||||
api(libs.room.ktx)
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.tenlionsoft.baselib.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
|
||||
class AndroidBug5497Workaround(activity: Activity, height: Int, hideBar: Boolean) {
|
||||
companion object {
|
||||
/**
|
||||
* height:通过外部传入,初始界面高度,用于改变界面后恢复原样,建议在activity的onWindowFocusChanged中初始化
|
||||
* hideBar:是否隐藏状态栏,用于这个是用户可以控制的,所以采用外部传入
|
||||
*/
|
||||
fun assistActivity(activity: Activity, height: Int, hideBar: Boolean = false) {
|
||||
AndroidBug5497Workaround(activity, height, hideBar)
|
||||
}
|
||||
}
|
||||
|
||||
private val mChildOfContent: View
|
||||
private var usableHeightPrevious: Int = 0
|
||||
private val frameLayoutParams: FrameLayout.LayoutParams
|
||||
private val contentHeight: Int
|
||||
private val statusBarHeight: Int
|
||||
|
||||
init {
|
||||
val content: FrameLayout = activity.findViewById(android.R.id.content)
|
||||
contentHeight = height
|
||||
mChildOfContent = content.getChildAt(0)
|
||||
statusBarHeight = if (hideBar) getStatusBarHeight(activity) else 0
|
||||
|
||||
mChildOfContent.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
possiblyResizeChildOfContent()
|
||||
}
|
||||
frameLayoutParams = mChildOfContent.layoutParams as FrameLayout.LayoutParams
|
||||
}
|
||||
|
||||
|
||||
private fun possiblyResizeChildOfContent() {
|
||||
val usableHeightNow = computeUsableHeight()
|
||||
if (usableHeightNow != usableHeightPrevious) {
|
||||
val usableHeightSansKeyboard = mChildOfContent.rootView.height
|
||||
val heightDifference = usableHeightSansKeyboard - usableHeightNow
|
||||
if (heightDifference > (usableHeightSansKeyboard / 4)) {
|
||||
// keyboard probably just became visible
|
||||
frameLayoutParams.height =
|
||||
usableHeightSansKeyboard - heightDifference + statusBarHeight
|
||||
} else {
|
||||
// keyboard probably just became hidden
|
||||
frameLayoutParams.height = contentHeight + statusBarHeight
|
||||
}
|
||||
mChildOfContent.requestLayout()
|
||||
usableHeightPrevious = usableHeightNow
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeUsableHeight(): Int {
|
||||
val r = Rect()
|
||||
mChildOfContent.getWindowVisibleDisplayFrame(r)
|
||||
return (r.bottom - r.top)
|
||||
}
|
||||
|
||||
private fun getStatusBarHeight(activity: Activity): Int {
|
||||
|
||||
return activity.resources.run {
|
||||
//获取status_bar_height资源的ID
|
||||
val resourceId = getIdentifier(
|
||||
"status_bar_height",
|
||||
"dimen",
|
||||
"android"
|
||||
)
|
||||
if (resourceId > 0) {
|
||||
//根据资源ID获取响应的尺寸值
|
||||
getDimensionPixelSize(resourceId)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,31 @@
|
||||
package com.tenlionsoft.baselib.base
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tenlionsoft.baselib.R
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
abstract class BaseActivity : DataBindingActivity() {
|
||||
//点击空白隐藏软键盘
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
Log.e("BaseActivity", "onTouchEvent: ")
|
||||
val v = currentFocus
|
||||
if (v != null && v is EditText) {
|
||||
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(v.windowToken, 0)
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
|
||||
fun exitApp() {
|
||||
android.os.Process.killProcess(android.os.Process.myPid()); //获取PID
|
||||
exitProcess(0); //常规java、c#的标准退出法,返回值为0代表正常退出
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.tenlionsoft.baselib.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -35,6 +36,7 @@ abstract class BaseBindingAdapter<D, I : ViewDataBinding>(
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun setData(list: List<D>) {
|
||||
Log.e("BaseBindingAdapter", "setData: $list")
|
||||
this.list = list
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
|
@ -1,7 +1,45 @@
|
||||
package com.tenlionsoft.baselib.utils
|
||||
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
object TimeUtils {
|
||||
private val SDF_THREAD_LOCAL: ThreadLocal<SimpleDateFormat> = ThreadLocal()
|
||||
private fun getDefaultFormat(): SimpleDateFormat {
|
||||
var simpleDateFormat: SimpleDateFormat? = SDF_THREAD_LOCAL.get()
|
||||
if (simpleDateFormat == null) {
|
||||
simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
|
||||
SDF_THREAD_LOCAL.set(simpleDateFormat)
|
||||
}
|
||||
return simpleDateFormat
|
||||
}
|
||||
|
||||
private fun getHoursFormat(): SimpleDateFormat {
|
||||
var simpleDateFormat: SimpleDateFormat? = SDF_THREAD_LOCAL.get()
|
||||
if (simpleDateFormat == null) {
|
||||
simpleDateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
SDF_THREAD_LOCAL.set(simpleDateFormat)
|
||||
}
|
||||
return simpleDateFormat
|
||||
}
|
||||
|
||||
fun getNowDateMillis(): Long {
|
||||
return System.currentTimeMillis()
|
||||
}
|
||||
|
||||
fun millis2String(millis: Long): String {
|
||||
return getDefaultFormat().format(Date(millis))
|
||||
}
|
||||
|
||||
fun millis2HMStr(millis: Long): String {
|
||||
return getHoursFormat().format(Date(millis))
|
||||
}
|
||||
|
||||
fun millis2String(millis: Long, format: DateFormat): String {
|
||||
return format.format(Date(millis))
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.tenlionsoft.baselib.widget
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.Rect
|
||||
import android.view.ViewTreeObserver
|
||||
|
||||
class SoftKeyBoardListener {
|
||||
fun setChangeListener(
|
||||
activity: Activity,
|
||||
funShow: (i: Int) -> Unit,
|
||||
funHide: (i: Int) -> Unit
|
||||
) {
|
||||
//纪录根视图的显示高度
|
||||
var rootViewVisibleHeight = 0
|
||||
//获取activity的根视图
|
||||
val rootView = activity.window.decorView
|
||||
|
||||
//监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
|
||||
rootView.viewTreeObserver.addOnGlobalLayoutListener(
|
||||
//获取当前根视图在屏幕上显示的大小
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
val r = Rect()
|
||||
rootView.getWindowVisibleDisplayFrame(r)
|
||||
val visibleHeight = r.height()
|
||||
|
||||
if (rootViewVisibleHeight == 0) {
|
||||
rootViewVisibleHeight = visibleHeight
|
||||
return@OnGlobalLayoutListener
|
||||
}
|
||||
|
||||
//根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
|
||||
if (rootViewVisibleHeight == visibleHeight) {
|
||||
return@OnGlobalLayoutListener
|
||||
}
|
||||
|
||||
//根视图显示高度变小超过200,可以看作软键盘显示了
|
||||
if (rootViewVisibleHeight - visibleHeight > 200) {
|
||||
funShow(rootViewVisibleHeight - visibleHeight)
|
||||
rootViewVisibleHeight = visibleHeight
|
||||
return@OnGlobalLayoutListener
|
||||
}
|
||||
|
||||
//根视图显示高度变大超过200,可以看作软键盘隐藏了
|
||||
if (visibleHeight - rootViewVisibleHeight > 200) {
|
||||
funHide(visibleHeight - rootViewVisibleHeight)
|
||||
rootViewVisibleHeight = visibleHeight
|
||||
return@OnGlobalLayoutListener
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="5dp" />
|
||||
<solid android:color="#D0A4A4A4" />
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="#FFFFFF" />
|
||||
|
||||
</shape>
|
@ -35,7 +35,8 @@ smartRefreshLayout = "2.1.0"
|
||||
jjwt = "3.10.3"
|
||||
emoji2Emojipicker = "1.0.0-alpha03"
|
||||
xxpermissions = "20.0"
|
||||
filepicker="2.0.0"
|
||||
filepicker = "2.0.0"
|
||||
room-ktx = "2.2.5"
|
||||
|
||||
|
||||
[libraries]
|
||||
@ -84,8 +85,8 @@ refreshMaterial = { group = "io.github.scwang90", name = "refresh-header-materia
|
||||
jjwt = { group = "com.auth0", name = "java-jwt", version.ref = "jjwt" }
|
||||
emojipicker = { group = "androidx.emoji2", name = "emoji2-emojipicker", version.ref = "emoji2Emojipicker" }
|
||||
xxpermissions = { group = "com.github.getActivity", name = "XXPermissions", version.ref = "xxpermissions" }
|
||||
filepicker={group="com.github.atwa",name="filepicker",version.ref="filepicker"}
|
||||
|
||||
filepicker = { group = "com.github.atwa", name = "filepicker", version.ref = "filepicker" }
|
||||
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room-ktx" }
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
|
Loading…
Reference in New Issue
Block a user