发送文件,图片,视频,处理失败

This commit is contained in:
itgaojian 2024-11-04 17:36:18 +08:00
parent 0d841e370d
commit db9ad383fa
35 changed files with 844 additions and 138 deletions

View File

@ -5,10 +5,12 @@ import android.view.ViewGroup
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgMyAudioBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgMyAudioBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgMyBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgMyBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgMyFileBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgMyImgBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgMyImgBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgMyVideoBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgMyVideoBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherAudioBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherAudioBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherFileBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherImgBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherImgBinding
import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherVideoBinding import com.tenlionsoft.aimz_k.databinding.ItemMsgOtherVideoBinding
import com.tenlionsoft.aimz_k.model.MsgBean import com.tenlionsoft.aimz_k.model.MsgBean
@ -16,67 +18,90 @@ import com.tenlionsoft.aimz_k.model.MsgTypeStateEnum
import com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel import com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel
import com.tenlionsoft.baselib.base.BaseBindingAdapter import com.tenlionsoft.baselib.base.BaseBindingAdapter
class ChatMsgAdapter(datas: List<MsgBean>, viewModel: ChatPageViewModel) : class ChatMsgAdapter(datas: List<MsgBean>, val viewModel: ChatPageViewModel) :
BaseBindingAdapter<MsgBean, ViewDataBinding>(datas) { BaseBindingAdapter<MsgBean, ViewDataBinding>(datas) {
override fun getItemBinding(parent: ViewGroup, viewType: Int): ViewDataBinding { override fun getItemBinding(parent: ViewGroup, viewType: Int): ViewDataBinding {
when (viewType) { when (viewType) {
MsgTypeStateEnum.MSG_TO_OTHER_TXT -> { //发送文本
MsgTypeStateEnum.MSG_TO_OTHER_TXT ->
return ItemMsgOtherBinding.inflate( return ItemMsgOtherBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//发送文本
MsgTypeStateEnum.MSG_FROM_OTHER_TXT -> { //收到文本信息
MsgTypeStateEnum.MSG_FROM_OTHER_TXT ->
return ItemMsgMyBinding.inflate( return ItemMsgMyBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//收到文本信息
MsgTypeStateEnum.MSG_TO_OTHER_MOVIE -> { //发送视频
return ItemMsgMyVideoBinding.inflate( MsgTypeStateEnum.MSG_TO_OTHER_MOVIE ->
LayoutInflater.from(parent.context),
parent,
false
)
}//发送视频
MsgTypeStateEnum.MSG_FROM_OTHER_MOVIE -> {
return ItemMsgOtherVideoBinding.inflate( return ItemMsgOtherVideoBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//收到视频
MsgTypeStateEnum.MSG_TO_OTHER_IMG -> { //收到视频
return ItemMsgMyImgBinding.inflate( MsgTypeStateEnum.MSG_FROM_OTHER_MOVIE ->
return ItemMsgMyVideoBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//发送图片
MsgTypeStateEnum.MSG_FROM_OTHER_IMG -> { //发送图片
MsgTypeStateEnum.MSG_TO_OTHER_IMG ->
return ItemMsgOtherImgBinding.inflate( return ItemMsgOtherImgBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//收到图片
MsgTypeStateEnum.MSG_TO_OTHER_VOICE -> { //收到图片
MsgTypeStateEnum.MSG_FROM_OTHER_IMG ->
return ItemMsgMyImgBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
//语音
MsgTypeStateEnum.MSG_TO_OTHER_VOICE ->
return ItemMsgMyAudioBinding.inflate( return ItemMsgMyAudioBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//语音 //语音
MsgTypeStateEnum.MSG_FROM_OTHER_VOICE -> { MsgTypeStateEnum.MSG_FROM_OTHER_VOICE ->
return ItemMsgOtherAudioBinding.inflate( return ItemMsgOtherAudioBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
}//语音 //发送文件
MsgTypeStateEnum.MSG_TO_OTHER_FILE ->
return ItemMsgOtherFileBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
//收到文件
MsgTypeStateEnum.MSG_FROM_OTHER_FILE -> {
return ItemMsgMyFileBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
}
else -> { else -> {
throw IllegalArgumentException("Invalid view type") throw IllegalArgumentException("Invalid view type")
} }
@ -89,6 +114,9 @@ class ChatMsgAdapter(datas: List<MsgBean>, viewModel: ChatPageViewModel) :
override fun bindItem(holder: BaseViewHolder<ViewDataBinding>, position: Int) { override fun bindItem(holder: BaseViewHolder<ViewDataBinding>, position: Int) {
val itemType = getItemViewType(position) val itemType = getItemViewType(position)
holder.binding.root.setOnClickListener {
viewModel.onItemClickListener?.onItemClick(list[position])
}
when (itemType) { when (itemType) {
//发送文本 //发送文本
MsgTypeStateEnum.MSG_TO_OTHER_TXT -> { MsgTypeStateEnum.MSG_TO_OTHER_TXT -> {
@ -104,28 +132,28 @@ class ChatMsgAdapter(datas: List<MsgBean>, viewModel: ChatPageViewModel) :
} }
//发送视频 //发送视频
MsgTypeStateEnum.MSG_TO_OTHER_MOVIE -> { 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).pos = position
(holder.binding as ItemMsgOtherVideoBinding).bean = list[position] (holder.binding as ItemMsgOtherVideoBinding).bean = list[position]
(holder.binding as ItemMsgOtherVideoBinding).state = list[position].status (holder.binding as ItemMsgOtherVideoBinding).state = list[position].status
} }
//收到视频
MsgTypeStateEnum.MSG_FROM_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_TO_OTHER_IMG -> { 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).pos = position
(holder.binding as ItemMsgOtherImgBinding).bean = list[position] (holder.binding as ItemMsgOtherImgBinding).bean = list[position]
(holder.binding as ItemMsgOtherImgBinding).state = list[position].status (holder.binding as ItemMsgOtherImgBinding).state = list[position].status
} }
//收到图片
MsgTypeStateEnum.MSG_FROM_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_TO_OTHER_VOICE -> { MsgTypeStateEnum.MSG_TO_OTHER_VOICE -> {
(holder.binding as ItemMsgMyAudioBinding).pos = position (holder.binding as ItemMsgMyAudioBinding).pos = position
@ -138,6 +166,18 @@ class ChatMsgAdapter(datas: List<MsgBean>, viewModel: ChatPageViewModel) :
(holder.binding as ItemMsgOtherAudioBinding).bean = list[position] (holder.binding as ItemMsgOtherAudioBinding).bean = list[position]
(holder.binding as ItemMsgOtherAudioBinding).state = list[position].status (holder.binding as ItemMsgOtherAudioBinding).state = list[position].status
} }
//发送文件
MsgTypeStateEnum.MSG_TO_OTHER_FILE -> {
(holder.binding as ItemMsgOtherFileBinding).pos = position
(holder.binding as ItemMsgOtherFileBinding).bean = list[position]
(holder.binding as ItemMsgOtherFileBinding).state = list[position].status
}
//收到文件
MsgTypeStateEnum.MSG_FROM_OTHER_FILE -> {
(holder.binding as ItemMsgMyFileBinding).pos = position
(holder.binding as ItemMsgMyFileBinding).bean = list[position]
(holder.binding as ItemMsgMyFileBinding).state = list[position].status
}
else -> { else -> {
throw IllegalArgumentException("Invalid view type") throw IllegalArgumentException("Invalid view type")

View File

@ -0,0 +1,14 @@
package com.tenlionsoft.aimz_k.model
data class FileUploadStateBean(var code: Int, var data: FileDataBean)
//"fileId": "2b9dfe0b-ef6f-466c-84f6-8aedb7c97d8f",
//"fileName": "Screenshot_20230626_092232.jpg",
//"fileSize": 103874,
//"fileUrl": "api/file/download/2b9dfe0b-ef6f-466c-84f6-8aedb7c97d8f"
data class FileDataBean(
var fileId: String?,
var fileName: String?,
var fileSize: Long?,
var fileUrl: String
)

View File

@ -1,6 +1,7 @@
package com.tenlionsoft.aimz_k.net package com.tenlionsoft.aimz_k.net
import com.tenlionsoft.aimz_k.model.BaseSuccessBean import com.tenlionsoft.aimz_k.model.BaseSuccessBean
import com.tenlionsoft.aimz_k.model.FileUploadStateBean
import com.tenlionsoft.baselib.model.VersionBean import com.tenlionsoft.baselib.model.VersionBean
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
@ -23,6 +24,7 @@ interface UserApi {
@Headers("Content-Type: application/json", "Accept: application/json", "projectName:usercenter") @Headers("Content-Type: application/json", "Accept: application/json", "projectName:usercenter")
@POST("api/jwt/login") @POST("api/jwt/login")
suspend fun doLogin(@Body user: RequestBody): BaseSuccessBean suspend fun doLogin(@Body user: RequestBody): BaseSuccessBean
/** /**
* 登陆Socket系统 * 登陆Socket系统
* http://192.168.0.26:8888/system/api/anonymous/login * http://192.168.0.26:8888/system/api/anonymous/login
@ -43,7 +45,7 @@ interface UserApi {
/** /**
* 上传图片文件 * 上传图片
* image * image
* *
* @param file * @param file
@ -52,8 +54,8 @@ interface UserApi {
*/ */
@Headers("token:need") @Headers("token:need")
@Multipart @Multipart
@POST("app/file/uploadimage") @POST("api/file/upload/image")
suspend fun doUploadImage(@Part file: MultipartBody.Part): BaseSuccessBean suspend fun doUploadImage(@Part file: MultipartBody.Part): FileUploadStateBean
/** /**
@ -66,6 +68,22 @@ interface UserApi {
*/ */
@Headers("token:need") @Headers("token:need")
@Multipart @Multipart
@POST("app/file/uploadvideo") @POST("api/file/upload/video")
fun doUploadVideo(@Part file: MultipartBody.Part): BaseSuccessBean suspend fun doUploadVideo(@Part file: MultipartBody.Part): FileUploadStateBean
/**
* 上传文件
*/
@Headers("token:need")
@Multipart
@POST("api/file/upload/file")
suspend fun doUploadFile(@Part file: MultipartBody.Part): FileUploadStateBean
/**
* 上传音频
*/
@Headers("token:need")
@Multipart
@POST("api/file/upload/audio")
suspend fun doUploadAudio(@Part file: MultipartBody.Part): FileUploadStateBean
} }

View File

@ -16,11 +16,15 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.atwa.filepicker.core.FilePicker import com.atwa.filepicker.core.FilePicker
import com.tenlionsoft.aimz_k.R import com.tenlionsoft.aimz_k.R
import com.tenlionsoft.aimz_k.databinding.ActivityChatBinding import com.tenlionsoft.aimz_k.databinding.ActivityChatBinding
import com.tenlionsoft.aimz_k.model.MsgBean
import com.tenlionsoft.aimz_k.model.PickerType import com.tenlionsoft.aimz_k.model.PickerType
import com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel import com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel
import com.tenlionsoft.baselib.base.BaseActivity import com.tenlionsoft.baselib.base.BaseActivity
import com.tenlionsoft.baselib.contacts.ProjectConfig import com.tenlionsoft.baselib.contacts.ProjectConfig
import com.tenlionsoft.baselib.utils.DensityUtils
import com.tenlionsoft.baselib.utils.SpUtils import com.tenlionsoft.baselib.utils.SpUtils
import com.tenlionsoft.baselib.widget.AdapterItemClickListener
import com.tenlionsoft.baselib.widget.LoadingDialog
import com.tenlionsoft.baselib.widget.SoftKeyBoardListener import com.tenlionsoft.baselib.widget.SoftKeyBoardListener
import com.tenlionsoft.baselib.widget.wheel.WheelView import com.tenlionsoft.baselib.widget.wheel.WheelView
@ -28,13 +32,14 @@ import com.tenlionsoft.baselib.widget.wheel.WheelView
/** /**
* 聊天页面 * 聊天页面
*/ */
class ChatActivity : BaseActivity() { class ChatActivity : BaseActivity(), AdapterItemClickListener<MsgBean> {
private lateinit var mBinding: ActivityChatBinding private lateinit var mBinding: ActivityChatBinding
private lateinit var mLocalReceiver: LocalReceiver private lateinit var mLocalReceiver: LocalReceiver
var chatPageViewModel: ChatPageViewModel? = null var chatPageViewModel: ChatPageViewModel? = null
private val filePicker = FilePicker.getInstance(this) private val filePicker = FilePicker.getInstance(this)
private var mContentHeight: Int = 0 private var mContentHeight: Int = 0
private var mLoading: LoadingDialog? = null;
private var bottomHeight = -1
override fun bindView() { override fun bindView() {
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_chat); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_chat);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
@ -43,9 +48,7 @@ class ChatActivity : BaseActivity() {
val fromId = intent.getStringExtra("fromId") //传递过来的接收人 val fromId = intent.getStringExtra("fromId") //传递过来的接收人
val name = intent.getStringExtra("name") val name = intent.getStringExtra("name")
if (name.isNullOrEmpty()) { mBinding.tvTitle.text = if (name.isNullOrEmpty()) "临时客户" else name
mBinding.tvTitle.text = "临时客户"
}
chatPageViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory { chatPageViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -54,7 +57,7 @@ class ChatActivity : BaseActivity() {
) as T ) as T
} }
})[ChatPageViewModel::class.java] })[ChatPageViewModel::class.java]
chatPageViewModel!!.onItemClickListener = this
mBinding.ivBack.setOnClickListener { finish(); } mBinding.ivBack.setOnClickListener { finish(); }
mBinding.viewModel = chatPageViewModel mBinding.viewModel = chatPageViewModel
mBinding.lifecycleOwner = this mBinding.lifecycleOwner = this
@ -63,27 +66,57 @@ class ChatActivity : BaseActivity() {
mBinding.etMsg.append(it.emoji) mBinding.etMsg.append(it.emoji)
} }
//显示/隐藏软键盘 chatPageViewModel!!.showReplyLayout.observe(this) {
// chatPageViewModel!!.showSoftKeyboard.observe(this) { if (it) {
// if (it) { hideSoftKeyboard()//隐藏软键盘
// showSoftKeyBoard(mBinding.etMsg) setContentLayoutHeight()
// chatPageViewModel!!.showChooseLayout.value = false } else {
// chatPageViewModel!!.showEmojiLayout.value = false val isShow =
// chatPageViewModel!!.showReplyLayout.value = false chatPageViewModel!!.showEmojiLayout.value!! || chatPageViewModel!!.showChooseLayout.value!!
// val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager if (isShow) {
// val itemCount = layoutManager.itemCount setContentDefaultHeight()
// mBinding.rlvChats.smoothScrollToPosition(itemCount - 1) }
// } else { }
// hideSoftKeyboard() }
// } chatPageViewModel!!.showEmojiLayout.observe(this) {
// } if (it) {
// mBinding.rlContent.setOnClickListener { hideSoftKeyboard()//隐藏软键盘
// Log.e("ChatActivity", "bindView: 点击") setContentLayoutHeight()
// chatPageViewModel!!.showChooseLayout.value = false } else {
// chatPageViewModel!!.showEmojiLayout.value = false val isShow =
// chatPageViewModel!!.showReplyLayout.value = false chatPageViewModel!!.showReplyLayout.value!! || chatPageViewModel!!.showChooseLayout.value!!
// hideSoftKeyboard() if (isShow) {
// } setContentDefaultHeight()
}
}
}
chatPageViewModel!!.showChooseLayout.observe(this) {
if (it) {
hideSoftKeyboard()//隐藏软键盘
setContentLayoutHeight()
} else {
val isShow =
chatPageViewModel!!.showEmojiLayout.value!! || chatPageViewModel!!.showReplyLayout.value!!
if (isShow) {
setContentDefaultHeight()
}
}
}
chatPageViewModel!!.showLoadDialog.observe(this) {
if (it) {
//显示loading
mLoading = LoadingDialog.Builder(this)
.setCancelOutside(false)
.setCancelable(false)
.setMessage("上传中...")
.create()
mLoading!!.show()
} else {
//隐藏loading
mLoading?.dismiss()
mLoading = null
}
}
mBinding.wvView.setTextSize(14F, isSp = true) mBinding.wvView.setTextSize(14F, isSp = true)
mBinding.wvView.setAutoFitTextSize(true) mBinding.wvView.setAutoFitTextSize(true)
mBinding.wvView.setOnItemSelectedListener(object : WheelView.OnItemSelectedListener { mBinding.wvView.setOnItemSelectedListener(object : WheelView.OnItemSelectedListener {
@ -91,6 +124,7 @@ class ChatActivity : BaseActivity() {
mBinding.etMsg.setText(data.toString()) mBinding.etMsg.setText(data.toString())
} }
}) })
chatPageViewModel!!.chooseType.observe(this) { chatPageViewModel!!.chooseType.observe(this) {
when (it) { when (it) {
PickerType.TYPE_PIC -> { PickerType.TYPE_PIC -> {
@ -121,7 +155,7 @@ class ChatActivity : BaseActivity() {
} }
} }
chatPageViewModel!!.scrollListToBottom.observe(this) { chatPageViewModel!!.scrollListToBottom.observe(this) {
Log.e("TAG", "bindView:滚动 ${it} ") Log.e("TAG", "bindView:滚动 $it ")
if (it) { if (it) {
val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager
val itemCount = layoutManager.itemCount val itemCount = layoutManager.itemCount
@ -136,14 +170,24 @@ class ChatActivity : BaseActivity() {
chatPageViewModel!!.scrollListToBottom.value = false chatPageViewModel!!.scrollListToBottom.value = false
} }
} }
mBinding.llBottomLayout.visibility = View.VISIBLE
mBinding.rlBottom.visibility = View.GONE mBinding.rlBottom.visibility = View.GONE
mBinding.rlvChats.viewTreeObserver.addOnGlobalLayoutListener { mBinding.rlvChats.viewTreeObserver.addOnGlobalLayoutListener {
mContentHeight = mBinding.rlvChats.height mContentHeight = mBinding.rlvChats.height
} }
mBinding.llBottomLayout.viewTreeObserver.addOnGlobalLayoutListener {
if (mBinding.llBottomLayout.height == 0) {
bottomHeight = DensityUtils.dp2px(this@ChatActivity, 300F)
} else {
bottomHeight = mBinding.llBottomLayout.height
}
}
SoftKeyBoardListener().setChangeListener(this@ChatActivity, SoftKeyBoardListener().setChangeListener(this@ChatActivity,
{ h -> { h ->
mBinding.llBottomLayout.visibility = View.VISIBLE Log.e("ChatActivity", "软键盘: 显示")
chatPageViewModel!!.showReplyLayout.value = false
chatPageViewModel!!.showEmojiLayout.value = false
chatPageViewModel!!.showChooseLayout.value = false
mBinding.rlBottom.visibility = View.VISIBLE mBinding.rlBottom.visibility = View.VISIBLE
//重置layout高度 //重置layout高度
val layoutParams = mBinding.rlvChats.layoutParams val layoutParams = mBinding.rlvChats.layoutParams
@ -158,16 +202,17 @@ class ChatActivity : BaseActivity() {
0 0
) )
}, 100) }, 100)
}, },
{ _ -> { _ ->
val layoutParams = mBinding.rlvChats.layoutParams Log.e("ChatActivity", "软键盘: 隐藏")
layoutParams.height = mContentHeight val isShowOther =
mBinding.rlvChats.layoutParams = layoutParams chatPageViewModel!!.showReplyLayout.value!! || chatPageViewModel!!.showEmojiLayout.value!! || chatPageViewModel!!.showChooseLayout.value!!
mBinding.llBottomLayout.visibility = View.VISIBLE if (!isShowOther) {
mBinding.rlBottom.visibility = View.GONE val layoutParams = mBinding.rlvChats.layoutParams
layoutParams.height = mContentHeight
mBinding.rlvChats.layoutParams = layoutParams
mBinding.rlBottom.visibility = View.GONE
}
}) })
registerLocalReceiver() registerLocalReceiver()
} }
@ -185,6 +230,31 @@ class ChatActivity : BaseActivity() {
unregisterReceiver(mLocalReceiver) unregisterReceiver(mLocalReceiver)
} }
private fun setContentLayoutHeight() {
mBinding.rlBottom.visibility = View.VISIBLE
//重置layout高度
val layoutParams = mBinding.rlvChats.layoutParams
layoutParams.height = mContentHeight - bottomHeight
Log.e("ChatActivity", "setContentLayoutHeight: $mContentHeight $bottomHeight")
mBinding.rlvChats.layoutParams = layoutParams
val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager
val itemCount = layoutManager.itemCount
//滚动到底部
mBinding.rlvChats.postDelayed({
layoutManager.scrollToPositionWithOffset(
itemCount - 1,
0
)
}, 100)
}
private fun setContentDefaultHeight() {
val layoutParams = mBinding.rlvChats.layoutParams
layoutParams.height = mContentHeight
mBinding.rlvChats.layoutParams = layoutParams
mBinding.rlBottom.visibility = View.GONE
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
unRegisterLocalReceiver() unRegisterLocalReceiver()
@ -195,12 +265,17 @@ class ChatActivity : BaseActivity() {
when (intent?.action) { when (intent?.action) {
ProjectConfig.A_S_MSG_RECEIVER -> { ProjectConfig.A_S_MSG_RECEIVER -> {
val msg = intent.getStringExtra("msg") val msg = intent.getStringExtra("msg")
Log.e("LocalReceiver", "onReceive: ${msg}") Log.e("LocalReceiver", "onReceive: $msg")
chatPageViewModel!!.receiveMsg(msg) chatPageViewModel!!.receiveMsg(msg)
}//接收到信息 }//接收到信息
} }
} }
} }
//条目点击
override fun onItemClick(data: MsgBean) {
}
} }

View File

@ -10,8 +10,8 @@ import com.tenlionsoft.baselib.base.BaseActivity
import com.tenlionsoft.baselib.widget.LoadingDialog import com.tenlionsoft.baselib.widget.LoadingDialog
class LoginActivity : BaseActivity() { class LoginActivity : BaseActivity() {
private lateinit var mBinding: ActivityLoginBinding; private lateinit var mBinding: ActivityLoginBinding
private var mLoading: LoadingDialog? = null; private var mLoading: LoadingDialog? = null
private val loginPageViewModel: LoginPageViewModel by lazy { private val loginPageViewModel: LoginPageViewModel by lazy {
ViewModelProvider(this)[LoginPageViewModel::class.java] ViewModelProvider(this)[LoginPageViewModel::class.java]
} }
@ -40,13 +40,13 @@ class LoginActivity : BaseActivity() {
} }
loginPageViewModel.isLoginSuccess.observe(this) { loginPageViewModel.isLoginSuccess.observe(this) {
if (it) { if (it) {
// startActivity(Intent(this@LoginActivity, MainActivity::class.java)) startActivity(Intent(this@LoginActivity, MainActivity::class.java))
startActivity( // startActivity(
Intent( // Intent(
this@LoginActivity, // this@LoginActivity,
ChatActivity::class.java // ChatActivity::class.java
).putExtra("fromId", "2") // ).putExtra("fromId", "2").putExtra("name", "测试")
) // )
finish() finish()
} }
} }

View File

@ -90,7 +90,7 @@ class MainActivity : BaseActivity() {
return@setOnItemSelectedListener true; return@setOnItemSelectedListener true;
}//我的 }//我的
} }
false; false
} }
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {

View File

@ -17,9 +17,10 @@ import com.tenlionsoft.aimz_k.page.activity.MainActivity
import com.tenlionsoft.aimz_k.services.SocketService import com.tenlionsoft.aimz_k.services.SocketService
import com.tenlionsoft.aimz_k.viewmodel.MsgViewModel import com.tenlionsoft.aimz_k.viewmodel.MsgViewModel
import com.tenlionsoft.baselib.contacts.ProjectConfig import com.tenlionsoft.baselib.contacts.ProjectConfig
import com.tenlionsoft.baselib.widget.AdapterItemClickListener
import com.tenlionsoft.baselib.widget.LoadingDialog import com.tenlionsoft.baselib.widget.LoadingDialog
class MsgFragment : Fragment(), MsgViewModel.OnItemClickListener, class MsgFragment : Fragment(), AdapterItemClickListener<MsgCategoryBean>,
MainActivity.OnSocketConnectListener { MainActivity.OnSocketConnectListener {
private lateinit var mMsgBinding: FragmentMsgBinding private lateinit var mMsgBinding: FragmentMsgBinding
private var mActivity: MainActivity? = null private var mActivity: MainActivity? = null

View File

@ -59,6 +59,7 @@ class SocketService : Service(), WsManager.MsgCallBack {
} }
@SuppressLint("UnspecifiedRegisterReceiverFlag")
private fun registerLocalReceiver() { private fun registerLocalReceiver() {
val intentFilter = IntentFilter() val intentFilter = IntentFilter()
mLocalReceiver = LocalReceiver() mLocalReceiver = LocalReceiver()

View File

@ -2,6 +2,9 @@ package com.tenlionsoft.aimz_k.viewmodel
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@ -15,6 +18,7 @@ import com.tenlionsoft.aimz_k.adapter.ChatMsgAdapter
import com.tenlionsoft.aimz_k.model.BodyContent import com.tenlionsoft.aimz_k.model.BodyContent
import com.tenlionsoft.aimz_k.model.CoverSealedBean import com.tenlionsoft.aimz_k.model.CoverSealedBean
import com.tenlionsoft.aimz_k.model.DbManager import com.tenlionsoft.aimz_k.model.DbManager
import com.tenlionsoft.aimz_k.model.FileDataBean
import com.tenlionsoft.aimz_k.model.MsgBean import com.tenlionsoft.aimz_k.model.MsgBean
import com.tenlionsoft.aimz_k.model.MsgConvertBean import com.tenlionsoft.aimz_k.model.MsgConvertBean
import com.tenlionsoft.aimz_k.model.PickerType import com.tenlionsoft.aimz_k.model.PickerType
@ -23,9 +27,11 @@ import com.tenlionsoft.aimz_k.model.Sender
import com.tenlionsoft.aimz_k.net.UserApi import com.tenlionsoft.aimz_k.net.UserApi
import com.tenlionsoft.baselib.base.BaseViewModel import com.tenlionsoft.baselib.base.BaseViewModel
import com.tenlionsoft.baselib.contacts.ProjectConfig import com.tenlionsoft.baselib.contacts.ProjectConfig
import com.tenlionsoft.baselib.net.ExParse
import com.tenlionsoft.baselib.net.RetrofitClient import com.tenlionsoft.baselib.net.RetrofitClient
import com.tenlionsoft.baselib.utils.SpUtils import com.tenlionsoft.baselib.utils.SpUtils
import com.tenlionsoft.baselib.utils.TimeUtils import com.tenlionsoft.baselib.utils.TimeUtils
import com.tenlionsoft.baselib.widget.AdapterItemClickListener
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -34,7 +40,6 @@ import okhttp3.MultipartBody
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.asRequestBody
class ChatPageViewModel( class ChatPageViewModel(
private val fromId: String, private val fromId: String,
private val toId: String, private val toId: String,
@ -51,7 +56,34 @@ class ChatPageViewModel(
private val retrofitClient = RetrofitClient.getInstance(context) private val retrofitClient = RetrofitClient.getInstance(context)
private val netApi = retrofitClient.create(UserApi::class.java) private val netApi = retrofitClient.create(UserApi::class.java)
var adapter: ChatMsgAdapter = ChatMsgAdapter(_msgList.value ?: emptyList(), this) var adapter: ChatMsgAdapter = ChatMsgAdapter(_msgList.value ?: emptyList(), this)
var onItemClickListener: AdapterItemClickListener<MsgBean>? = null
private val mGson: Gson = Gson() private val mGson: Gson = Gson()
private var msgHandlerList: ArrayList<MsgConvertBean> = arrayListOf()
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val mBean: MsgConvertBean = msg.obj as MsgConvertBean
val isExist = msgHandlerList.contains(mBean)
if (isExist) {
// 更新数据库 发送失败
viewModelScope.launch {
withContext(Dispatchers.IO) {
val mDao = DbManager.db.msgDao()
val cDao = DbManager.db.categoryDao()
mDao.updateStatus(mBean.messageId, ProjectConfig.MSG_SEND_FAIL)
cDao.updateStatus(mBean.sender.senderId!!, ProjectConfig.MSG_SEND_FAIL)
}
for (item in _msgList.value!!) {
if (item.messageId == mBean.messageId) {
item.status = ProjectConfig.MSG_SEND_FAIL
}
}
adapter.setData(_msgList.value!!)
}
}
}
}
init { init {
Log.e("ChatPageViewModel", "Init: ${showSendBtn.value}") Log.e("ChatPageViewModel", "Init: ${showSendBtn.value}")
@ -78,20 +110,18 @@ class ChatPageViewModel(
} }
fun onShowReplyLayout() { fun onShowReplyLayout() {
showReplyLayout.value = !showReplyLayout.value!!
showEmojiLayout.value = false showEmojiLayout.value = false
showChooseLayout.value = false showChooseLayout.value = false
showSoftKeyboard.value = !showReplyLayout.value!! showReplyLayout.value = !showReplyLayout.value!!
} }
/** /**
* 切换emoji layout * 切换emoji layout
*/ */
fun onShowEmojiLayout() { fun onShowEmojiLayout() {
showEmojiLayout.value = !showEmojiLayout.value!!
showChooseLayout.value = false showChooseLayout.value = false
showReplyLayout.value = false showReplyLayout.value = false
showSoftKeyboard.value = !showEmojiLayout.value!! showEmojiLayout.value = !showEmojiLayout.value!!
} }
@ -99,10 +129,9 @@ class ChatPageViewModel(
* 切换选择layout * 切换选择layout
*/ */
fun onShowChooseLayout() { fun onShowChooseLayout() {
showChooseLayout.value = !showChooseLayout.value!!
showEmojiLayout.value = false showEmojiLayout.value = false
showReplyLayout.value = false showReplyLayout.value = false
showSoftKeyboard.value = !showChooseLayout.value!! showChooseLayout.value = !showChooseLayout.value!!
} }
/** /**
@ -134,11 +163,83 @@ class ChatPageViewModel(
return return
} }
viewModelScope.launch { viewModelScope.launch {
doUploadImgs(list) showLoadDialog.value = true
doUploadImages(list)
} }
} }
private suspend fun doUploadImgs(list: List<ImageMeta?>) {
/**
* 上传视频
*/
fun uploadVideo(meta: VideoMeta) {
viewModelScope.launch {
showLoadDialog.value = true
doUploadVideo(meta)
}
}
/**
* 上传文件
*/
fun uploadFiles(meta: FileMeta) {
viewModelScope.launch {
showLoadDialog.value = true
doUploadFile(meta)
}
}
private suspend fun doUploadVideo(meta: VideoMeta) {
try {
val requestFile: RequestBody =
meta.file!!.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val body: MultipartBody.Part =
MultipartBody.Part.createFormData(
"video",
meta.file!!.getName(),
requestFile
)
val bean = retrofitClient.makeApiCall {
netApi.doUploadVideo(body)
}
if (bean.code == 200) {
sendMedia(ProjectConfig.MSG_VIDEO, bean.data)
}
showLoadDialog.value = false
} catch (e: Exception) {
e.printStackTrace()
showLoadDialog.value = false
ExParse.parse(e)
}
}
private suspend fun doUploadFile(meta: FileMeta) {
try {
val requestFile: RequestBody =
meta.file!!.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val body: MultipartBody.Part =
MultipartBody.Part.createFormData(
"file",
meta.file!!.getName(),
requestFile
)
val bean = retrofitClient.makeApiCall {
netApi.doUploadFile(body)
}
if (bean.code == 200) {
sendMedia(ProjectConfig.MSG_FILE, bean.data)
}
showLoadDialog.value = false
} catch (e: Exception) {
e.printStackTrace()
showLoadDialog.value = false
ExParse.parse(e)
}
}
private var count: Int = 1
private suspend fun doUploadImages(list: List<ImageMeta?>) {
try { try {
for (item in list) { for (item in list) {
if (item != null) { if (item != null) {
@ -146,7 +247,7 @@ class ChatPageViewModel(
item.file!!.asRequestBody("multipart/form-data".toMediaTypeOrNull()) item.file!!.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val body: MultipartBody.Part = val body: MultipartBody.Part =
MultipartBody.Part.createFormData( MultipartBody.Part.createFormData(
"audio", "image",
item.file!!.getName(), item.file!!.getName(),
requestFile requestFile
) )
@ -154,35 +255,40 @@ class ChatPageViewModel(
val bean = retrofitClient.makeApiCall { val bean = retrofitClient.makeApiCall {
netApi.doUploadImage(body) netApi.doUploadImage(body)
} }
Log.e("ChatPageViewModel", "doUploadImgs: $bean")
if (bean.code == 200) { if (bean.code == 200) {
//上传成功 //上传成功
//TODO 构建消息实体 sendMedia(ProjectConfig.MSG_IMG, bean.data)
//TODO 发送消息
//
} else {
//TODO 上传失败
} }
++count
} }
} }
if (count == list.size) {
showLoadDialog.value = false
count = 1
}
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
showLoadDialog.value = false
count = 1
ExParse.parse(e)
} }
} }
/** //发送 图片/视频/音频/文件
* 上传视频 private fun sendMedia(type: String, data: FileDataBean) {
*/ val intent = Intent(ProjectConfig.A_S_MSG_SEND)
fun uploadVideo(meta: VideoMeta) { val b = buildSendMediaBean(type, data)
viewModelScope.launch {
val msgBean = insertMsgBeanToDb(b)
_msgList.value = _msgList.value?.plus(msgBean)
adapter.setData(_msgList.value!!)
}
intent.putExtra("msgBean", b)
context.sendBroadcast(intent)
scrollListToBottom.value = true
} }
/**
* 上传文件
*/
fun uploadFiles(meta: FileMeta) {
}
//刷新 //刷新
private fun refresh() { private fun refresh() {
@ -198,6 +304,7 @@ class ChatPageViewModel(
_msgList.value = _msgList.value?.plus(msgBean) _msgList.value = _msgList.value?.plus(msgBean)
adapter.setData(_msgList.value!!) adapter.setData(_msgList.value!!)
} }
/** /**
* 发送文本信息 * 发送文本信息
*/ */
@ -210,6 +317,10 @@ class ChatPageViewModel(
_msgList.value = _msgList.value?.plus(msgBean) _msgList.value = _msgList.value?.plus(msgBean)
adapter.setData(_msgList.value!!) adapter.setData(_msgList.value!!)
} }
// 保存发送信息到消息队列
//添加到消息队列
sendHandlerToLooper(b)
intent.putExtra("msgBean", b) intent.putExtra("msgBean", b)
v.context.sendBroadcast(intent) v.context.sendBroadcast(intent)
txtMsg.value = "" txtMsg.value = ""
@ -228,11 +339,18 @@ class ChatPageViewModel(
} }
} }
private fun sendHandlerToLooper(b: MsgConvertBean) {
msgHandlerList.add(b)
val msg = Message()
msg.what = b.timestamp.toInt()
msg.obj = b
handler.sendMessageDelayed(msg, 5000)
}
//收到消息 //收到消息
fun receiveMsg(msg: String?) { fun receiveMsg(msg: String?) {
if (!msg.isNullOrEmpty()) { if (!msg.isNullOrEmpty()) {
val bean = ConvertBeanUtils.covertBean(msg) when (val bean = ConvertBeanUtils.covertBean(msg)) {
when (bean) {
//消息状态 //消息状态
is CoverSealedBean.StateBean -> { is CoverSealedBean.StateBean -> {
viewModelScope.launch { viewModelScope.launch {
@ -244,6 +362,9 @@ class ChatPageViewModel(
dao.updateStatus(bean.data.messageId, statusType) dao.updateStatus(bean.data.messageId, statusType)
cDao.updateStatus(bean.data.sender.senderId!!, statusType) cDao.updateStatus(bean.data.sender.senderId!!, statusType)
} }
//删除队列里面的Bean
msgHandlerList.removeIf { it.messageId == bean.data.messageId }
handler.removeMessages(bean.data.timestamp.toInt())
refresh() refresh()
} }
} }
@ -275,7 +396,7 @@ class ChatPageViewModel(
context.sendBroadcast(intent) context.sendBroadcast(intent)
} }
//构建发送实体 //构建文字发送实体
private fun buildSendBean(type: String): MsgConvertBean { private fun buildSendBean(type: String): MsgConvertBean {
val bodyBean = BodyContent(content = txtMsg.value, null, null) val bodyBean = BodyContent(content = txtMsg.value, null, null)
val body = mGson.toJson(bodyBean) val body = mGson.toJson(bodyBean)
@ -298,6 +419,31 @@ class ChatPageViewModel(
) )
} }
//构建 图片/视频/文件发送实体
private fun buildSendMediaBean(type: String, fileBean: FileDataBean): MsgConvertBean {
val bodyBean = BodyContent(content = mGson.toJson(fileBean), null, null)
val body = mGson.toJson(bodyBean)
return MsgConvertBean(
body = body,
customMessageType = "",
messageId = TimeUtils.getNowDateMillis().toString(),
messageType = type,
metadata = "",
timestamp = TimeUtils.getNowDateMillis(),
sender = Sender(
senderId = SpUtils.getId(),
senderType = ""
),
receiver = Receiver(
receiverId = fromId,
receiverType = "SINGLE_USER"
),
status = ProjectConfig.MSG_SEND_ING,
)
}
//构建状态信息 //构建状态信息
private fun buildStatusBean(messageId: String): MsgConvertBean { private fun buildStatusBean(messageId: String): MsgConvertBean {
val bodyBean = BodyContent(content = null, msg = "", statusType = "SUCCESS_RECEIVED") val bodyBean = BodyContent(content = null, msg = "", statusType = "SUCCESS_RECEIVED")
@ -320,4 +466,7 @@ class ChatPageViewModel(
status = "", status = "",
) )
} }
}
}

View File

@ -37,7 +37,7 @@ class LoginPageViewModel : BaseViewModel() {
} }
fun doLogin() { fun doLogin() {
isLoginSuccess.value = true // isLoginSuccess.value= true
val isLegal = checkParams(); val isLegal = checkParams();
if (isLegal) { if (isLegal) {
viewModelScope.launch { viewModelScope.launch {

View File

@ -19,6 +19,7 @@ import com.tenlionsoft.aimz_k.model.Sender
import com.tenlionsoft.baselib.contacts.ProjectConfig import com.tenlionsoft.baselib.contacts.ProjectConfig
import com.tenlionsoft.baselib.utils.SpUtils import com.tenlionsoft.baselib.utils.SpUtils
import com.tenlionsoft.baselib.utils.TimeUtils import com.tenlionsoft.baselib.utils.TimeUtils
import com.tenlionsoft.baselib.widget.AdapterItemClickListener
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -26,7 +27,7 @@ import kotlinx.coroutines.withContext
class MsgViewModel : ViewModel() { class MsgViewModel : ViewModel() {
private val _pwdList = MutableLiveData<List<MsgCategoryBean>>() 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 var onItemClickListener: AdapterItemClickListener<MsgCategoryBean>? = null
val isLogining = MutableLiveData(false) val isLogining = MutableLiveData(false)
private val mGson = Gson() private val mGson = Gson()
private var mCurrentPage: Int = 1 private var mCurrentPage: Int = 1
@ -156,8 +157,4 @@ class MsgViewModel : ViewModel() {
fun refresh() { fun refresh() {
getList(true) getList(true)
} }
interface OnItemClickListener {
fun onItemClick(msgCategoryBean: MsgCategoryBean)
}
} }

View File

@ -1,5 +1,8 @@
package com.tenlionsoft.aimz_k.widget package com.tenlionsoft.aimz_k.widget
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.util.Log
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
@ -10,11 +13,18 @@ import androidx.recyclerview.widget.RecyclerView.Adapter
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.gson.Gson import com.google.gson.Gson
import com.tenlionsoft.aimz_k.R import com.tenlionsoft.aimz_k.R
import com.tenlionsoft.aimz_k.model.BodyContent import com.tenlionsoft.aimz_k.model.BodyContent
import com.tenlionsoft.aimz_k.model.FileDataBean
import com.tenlionsoft.baselib.contacts.NetConfig
import com.tenlionsoft.baselib.contacts.ProjectConfig import com.tenlionsoft.baselib.contacts.ProjectConfig
import com.tenlionsoft.baselib.model.ImageSize
import com.tenlionsoft.baselib.utils.ImageUtils
import com.tenlionsoft.baselib.utils.TimeUtils import com.tenlionsoft.baselib.utils.TimeUtils
import com.tenlionsoft.baselib.widget.chat.BubbleImageView
object BindingUtils { object BindingUtils {
@ -61,7 +71,131 @@ object BindingUtils {
} else { } else {
val gson = Gson() val gson = Gson()
val body = gson.fromJson(str, BodyContent::class.java) val body = gson.fromJson(str, BodyContent::class.java)
tv.text = body.content val contains = body.content!!.contains("fileName")
if (contains) {
tv.text = "文件"
} else {
tv.text = body.content
}
}
}
@BindingAdapter("jsonConvertMsgFileIcon")
@JvmStatic
fun jsonConvertFileIcon(iv: ImageView, str: String?) {
if (str.isNullOrEmpty()) {
iv.visibility = View.GONE
} else {
iv.visibility = View.VISIBLE
val gson = Gson()
val body = gson.fromJson(str, BodyContent::class.java)
val contains = body.content!!.contains("fileName")
if (contains) {
val fileDataBean = gson.fromJson(body.content, FileDataBean::class.java)
if (!fileDataBean.fileName.isNullOrEmpty()) {
iv.visibility = View.VISIBLE
val suffix = fileDataBean.fileName!!.substring(
fileDataBean.fileName!!.lastIndexOf("."),
fileDataBean.fileName!!.length
)
Log.e("BindingUtils", "jsonConvertFileIcon: $suffix")
var id = R.drawable.ic_audio
when (suffix) {
".zip", ".rar", ".7z", ".gz", ".xz" -> iv.setImageResource(R.drawable.ic_zip)
".png", ".jpg", ".jpeg", ".svg", ".gif" -> iv.setImageResource(R.drawable.ic_image)
".doc", ".docx", ".wps", ".wpt" -> iv.setImageResource(R.drawable.ic_word)
".xls", ".xlsx", ".et", ".ett" -> iv.setImageResource(R.drawable.ic_excel)
".pdf" -> iv.setImageResource(R.drawable.ic_pdf)
else -> iv.setImageResource(R.drawable.ic_file)
}
} else {
iv.visibility = View.GONE
}
} else {
iv.visibility = View.GONE
}
}
}
@BindingAdapter("jsonConvertMsgFileName")
@JvmStatic
fun jsonConvertFileName(tv: TextView, str: String?) {
if (str.isNullOrEmpty()) {
tv.text = ""
} else {
val gson = Gson()
val body = gson.fromJson(str, BodyContent::class.java)
val contains = body.content!!.contains("fileName")
if (contains) {
val fileBean = gson.fromJson(body.content, FileDataBean::class.java)
tv.text = fileBean.fileName
} else {
tv.text = body.content
}
}
}
@BindingAdapter("jsonConvertMsgAudioImg")
@JvmStatic
fun jsonConvertAudioCover(iv: ImageView, str: String?) {
if (str.isNullOrEmpty()) {
iv.setImageResource(com.tenlionsoft.baselib.R.drawable.ic_img_load_err)
} else {
val options: RequestOptions = RequestOptions()
.placeholder(com.tenlionsoft.baselib.R.drawable.ic_loading) // 正在加载中的图片
.error(com.tenlionsoft.baselib.R.drawable.ic_img_load_err) // 加载失败的图片
val gson = Gson()
val bodyContent = gson.fromJson<BodyContent>(str, BodyContent::class.java)
val fileBean = gson.fromJson(bodyContent.content, FileDataBean::class.java)
Glide.with(iv.context)
.load(NetConfig.MAIN_URL + fileBean.fileUrl) // 图片地址
.apply(options)
.into(object : CustomTarget<Drawable?>() {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable?>?
) {
val imageSize: ImageSize? =
ImageUtils.getImageSize((resource as BitmapDrawable).bitmap)
if (imageSize != null) {
val imageLP = iv.layoutParams
imageLP?.width = imageSize.getWidth()
imageLP?.height = imageSize.getHeight()
iv.setLayoutParams(imageLP)
Glide.with(iv.context)
.load(resource)
.apply(options) // 参数
.into(iv)
}
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
}
}
@BindingAdapter("jsonConvertMsgImgBody")
@JvmStatic
fun jsonConvertImg(view: BubbleImageView, str: String?) {
if (str.isNullOrEmpty()) {
view.setImageResource(com.tenlionsoft.baselib.R.drawable.ic_load_error)
} else {
val gson = Gson()
val body = gson.fromJson(str, BodyContent::class.java)
val fileData = gson.fromJson(body.content, FileDataBean::class.java)
val requestOptions = RequestOptions()
.error(R.drawable.app_logo_small)
.placeholder(R.drawable.app_logo_small)
.skipMemoryCache(false)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerInside()
Glide.with(view.context)
.load(NetConfig.MAIN_URL + fileData.fileUrl)
.apply(requestOptions)
.into(view)
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

View File

@ -73,7 +73,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:background="@color/green"
tools:listitem="@layout/item_msg_my" /> tools:listitem="@layout/item_msg_my" />

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="pos"
type="Integer" />
<variable
name="bean"
type="com.tenlionsoft.aimz_k.model.MsgBean" />
<variable
name="state"
type="String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_margin="5dp"
android:orientation="horizontal"
android:padding="8dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_weight="1"
android:gravity="end">
<RelativeLayout
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_toLeftOf="@id/tv_content">
<ProgressBar
android:id="@+id/pb_sending"
isShowLoading="@{state}"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerInParent="true"
android:indeterminateBehavior="repeat"
android:indeterminateDrawable="@drawable/anim_loading" />
<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"
tools:visibility="visible" />
</RelativeLayout>
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:background="@drawable/ic_message_text_send"
android:orientation="horizontal">
<ImageView
jsonConvertMsgFileIcon="@{bean.body}"
android:layout_width="32dp"
android:layout_height="32dp"
android:scaleType="fitXY" />
<TextView
jsonConvertMsgFileName="@{bean.body}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="文件名称文件名称文件名称文件名称文件名称文件名称.jpg" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/iv_user_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:scaleType="fitXY"
android:src="@drawable/ic_user_default" />
</LinearLayout>
</layout>

View File

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<data> <data>
<variable <variable
name="pos" name="pos"
type="Integer" /> type="Integer" />
@ -11,6 +12,7 @@
<variable <variable
name="bean" name="bean"
type="com.tenlionsoft.aimz_k.model.MsgBean" /> type="com.tenlionsoft.aimz_k.model.MsgBean" />
<variable <variable
name="state" name="state"
type="String" /> type="String" />
@ -41,19 +43,19 @@
<ProgressBar <ProgressBar
android:id="@+id/pb_sending" android:id="@+id/pb_sending"
isShowLoading="@{state}"
android:layout_width="15dp" android:layout_width="15dp"
android:layout_height="15dp" android:layout_height="15dp"
android:layout_centerInParent="true" android:layout_centerInParent="true"
isShowLoading="@{state}"
android:indeterminateBehavior="repeat" android:indeterminateBehavior="repeat"
android:indeterminateDrawable="@drawable/anim_loading" /> android:indeterminateDrawable="@drawable/anim_loading" />
<ImageView <ImageView
android:id="@+id/iv_msg_state_fail" android:id="@+id/iv_msg_state_fail"
isShowFail="@{state}"
android:layout_width="15dp" android:layout_width="15dp"
android:layout_height="15dp" android:layout_height="15dp"
android:layout_centerInParent="true" android:layout_centerInParent="true"
isShowFail="@{state}"
android:src="@drawable/msg_state_fail_resend" android:src="@drawable/msg_state_fail_resend"
tools:visibility="visible" /> tools:visibility="visible" />
</RelativeLayout> </RelativeLayout>
@ -68,6 +70,7 @@
<com.tenlionsoft.baselib.widget.chat.BubbleImageView <com.tenlionsoft.baselib.widget.chat.BubbleImageView
android:id="@+id/iv_content" android:id="@+id/iv_content"
jsonConvertMsgImgBody="@{bean.body}"
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"

View File

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<data> <data>
<variable <variable
name="pos" name="pos"
type="Integer" /> type="Integer" />
@ -11,6 +12,7 @@
<variable <variable
name="bean" name="bean"
type="com.tenlionsoft.aimz_k.model.MsgBean" /> type="com.tenlionsoft.aimz_k.model.MsgBean" />
<variable <variable
name="state" name="state"
type="String" />> type="String" />>
@ -41,18 +43,18 @@
<ProgressBar <ProgressBar
android:id="@+id/pb_sending" android:id="@+id/pb_sending"
isShowLoading="@{state}"
android:layout_width="15dp" android:layout_width="15dp"
android:layout_height="15dp" android:layout_height="15dp"
isShowLoading="@{state}"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:indeterminateBehavior="repeat" android:indeterminateBehavior="repeat"
android:indeterminateDrawable="@drawable/anim_loading" /> android:indeterminateDrawable="@drawable/anim_loading" />
<ImageView <ImageView
android:id="@+id/iv_msg_state_fail" android:id="@+id/iv_msg_state_fail"
isShowFail="@{state}"
android:layout_width="15dp" android:layout_width="15dp"
android:layout_height="15dp" android:layout_height="15dp"
isShowFail="@{state}"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:src="@drawable/msg_state_fail_resend" android:src="@drawable/msg_state_fail_resend"
tools:visibility="visible" /> tools:visibility="visible" />
@ -68,8 +70,9 @@
<com.tenlionsoft.baselib.widget.chat.BubbleImageView <com.tenlionsoft.baselib.widget.chat.BubbleImageView
android:id="@+id/iv_content" android:id="@+id/iv_content"
android:layout_width="100dp" jsonConvertMsgAudioImg="@{bean.body}"
android:layout_height="100dp" android:layout_width="120dp"
android:layout_height="120dp"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_marginStart="0dp" android:layout_marginStart="0dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="pos"
type="Integer" />
<variable
name="bean"
type="com.tenlionsoft.aimz_k.model.MsgBean" />
<variable
name="state"
type="String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="left"
android:padding="8dp">
<ImageView
android:id="@+id/iv_user_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="fitXY"
android:src="@drawable/ic_user_default" />
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:background="@drawable/ic_message_text_receive"
android:orientation="horizontal">
<TextView
jsonConvertMsgFileName="@{bean.body}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="文件名称文件名称文件名称文件名称文件名称文件名称.jpg" />
<ImageView
jsonConvertMsgFileIcon="@{bean.body}"
android:layout_width="32dp"
android:layout_height="32dp"
android:scaleType="fitXY" />
</LinearLayout>
<RelativeLayout
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp">
<ProgressBar
android:id="@+id/pb_sending"
isShowLoading="@{state}"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerInParent="true"
android:indeterminateBehavior="repeat"
android:indeterminateDrawable="@drawable/anim_loading" />
<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"
tools:visibility="visible" />
</RelativeLayout>
</LinearLayout>
</layout>

View File

@ -47,6 +47,7 @@
android:layout_marginStart="0dp" android:layout_marginStart="0dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleType="centerCrop" android:scaleType="centerCrop"
jsonConvertMsgImgBody="@{bean.body}"
android:transitionName="sharedView" android:transitionName="sharedView"
app:angle="6dp" app:angle="6dp"
app:arrowHeight="8dp" app:arrowHeight="8dp"

View File

@ -45,6 +45,7 @@
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
jsonConvertMsgAudioImg="@{bean.body}"
android:layout_marginStart="0dp" android:layout_marginStart="0dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleType="centerCrop" android:scaleType="centerCrop"

View File

@ -19,8 +19,9 @@ object ProjectConfig {
//消息类型 //消息类型
const val MSG_TEXT = "MSG_TEXT" const val MSG_TEXT = "MSG_TEXT"
const val MSG_FILE = "MSG_FILE" const val MSG_FILE = "MSG_FILE"
const val MSG_IMG = "MSG_IMG" const val MSG_IMG = "MSG_IMAGE"
const val MSG_VIDEO = "MSG_VIDEO" const val MSG_VIDEO = "MSG_VIDEO"
const val MSG_AUDIO = "MSG_AUDIO"
const val MSG_STATUS = "STATUS" //状态消息 const val MSG_STATUS = "STATUS" //状态消息
const val MSG_SEND_ING: String = "PENDING"//11 //发送中 const val MSG_SEND_ING: String = "PENDING"//11 //发送中
const val MSG_SEND_FAIL: String = "ERROR"//12 //发送失败 const val MSG_SEND_FAIL: String = "ERROR"//12 //发送失败

View File

@ -0,0 +1,21 @@
package com.tenlionsoft.baselib.model
class ImageSize {
private var width = 0
private var height = 0
fun getWidth(): Int {
return width
}
fun setWidth(width: Int) {
this.width = width
}
fun getHeight(): Int {
return height
}
fun setHeight(height: Int) {
this.height = height
}
}

View File

@ -1,5 +1,6 @@
package com.tenlionsoft.baselib.net package com.tenlionsoft.baselib.net
import android.util.Log
import com.tenlionsoft.baselib.contacts.NetConfig import com.tenlionsoft.baselib.contacts.NetConfig
import com.tenlionsoft.baselib.utils.SpUtils import com.tenlionsoft.baselib.utils.SpUtils
import okhttp3.HttpUrl import okhttp3.HttpUrl
@ -19,7 +20,10 @@ class BaseUrlInterceptor : Interceptor {
val oldHttpUrl = request.url; val oldHttpUrl = request.url;
val headers = request.headers("project"); val headers = request.headers("project");
//公共Token header //公共Token header
if (headers.indexOf("token") != -1) { val tokens = request.headers("token")
Log.e("BaseUrlInterceptor", "intercept: $tokens")
if (tokens.isNotEmpty()) {
Log.e("BaseUrlInterceptor", "intercept: 添加公共Header")
builder.removeHeader("token") builder.removeHeader("token")
builder.addHeader("X-WG-TOKEN", SpUtils.getToken()) builder.addHeader("X-WG-TOKEN", SpUtils.getToken())
builder.addHeader("X-WG-TYPE", "APP") builder.addHeader("X-WG-TYPE", "APP")
@ -43,7 +47,7 @@ class BaseUrlInterceptor : Interceptor {
.build(); .build();
return chain.proceed(builder.url(newFullUrl).build()); return chain.proceed(builder.url(newFullUrl).build());
} else { } else {
return chain.proceed(request); return chain.proceed(builder.url(oldHttpUrl).build());
} }
} }
} }

View File

@ -0,0 +1,62 @@
package com.tenlionsoft.baselib.utils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import com.tenlionsoft.baselib.model.ImageSize
import java.io.ByteArrayOutputStream
import java.io.IOException
object ImageUtils {
fun getImageSize(bitmap: Bitmap?): ImageSize? {
val imageSize: ImageSize = ImageSize()
if (null == bitmap || bitmap.isRecycled) {
return null
}
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val byteTmp = baos.toByteArray()
try {
baos.close()
} catch (e: IOException) {
e.printStackTrace()
}
val bitmapOptions = BitmapFactory.Options()
bitmapOptions.inJustDecodeBounds = true
BitmapFactory.decodeByteArray(byteTmp, 0, byteTmp.size, bitmapOptions)
val outWidth = bitmapOptions.outWidth
val outHeight = bitmapOptions.outHeight
val maxWidth = 400
val maxHeight = 400
val minWidth = 150
val minHeight = 150
if (outWidth / maxWidth > outHeight / maxHeight) { //
if (outWidth >= maxWidth) { //
imageSize.setWidth(maxWidth)
imageSize.setHeight(outHeight * maxWidth / outWidth)
} else {
imageSize.setWidth(outWidth)
imageSize.setHeight(outHeight)
}
if (outHeight < minHeight) {
imageSize.setHeight(minHeight)
val width = outWidth * minHeight / outHeight
imageSize.setWidth(Math.min(width, maxWidth))
}
} else {
if (outHeight >= maxHeight) {
imageSize.setHeight(maxHeight)
imageSize.setWidth(outWidth * maxHeight / outHeight)
} else {
imageSize.setHeight(outHeight)
imageSize.setWidth(outWidth)
}
if (outWidth < minWidth) {
imageSize.setWidth(minWidth)
val height = outHeight * minWidth / outWidth
imageSize.setHeight(Math.min(height, maxHeight))
}
}
return imageSize
}
}

View File

@ -0,0 +1,5 @@
package com.tenlionsoft.baselib.widget
interface AdapterItemClickListener<D> {
fun onItemClick(data: D)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB