diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 350275b..905f14f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,8 +29,7 @@ android:exported="false" /> + android:exported="false" /> create(modelClass: Class): T { return ChatPageViewModel( - fromId!!, - SpUtils.getId(), - this@ChatActivity.applicationContext + fromId!!, SpUtils.getId(), this@ChatActivity.applicationContext ) as T } })[ChatPageViewModel::class.java] mBinding.ivBack.setOnClickListener { finish(); } - mBinding.srlChats.setEnableRefresh(false) - mBinding.srlChats.setEnableLoadMore(false) mBinding.viewModel = chatPageViewModel mBinding.lifecycleOwner = this //选择emoji mBinding.rpvEmoji.setOnEmojiPickedListener { mBinding.etMsg.append(it.emoji) } + //显示/隐藏软键盘 // chatPageViewModel!!.showSoftKeyboard.observe(this) { // if (it) { @@ -78,13 +77,13 @@ class ChatActivity : BaseActivity() { // hideSoftKeyboard() // } // } - mBinding.rlContent.setOnClickListener { - Log.e("ChatActivity", "bindView: 点击") - chatPageViewModel!!.showChooseLayout.value = false - chatPageViewModel!!.showEmojiLayout.value = false - chatPageViewModel!!.showReplyLayout.value = false - hideSoftKeyboard() - } +// mBinding.rlContent.setOnClickListener { +// Log.e("ChatActivity", "bindView: 点击") +// chatPageViewModel!!.showChooseLayout.value = false +// chatPageViewModel!!.showEmojiLayout.value = false +// chatPageViewModel!!.showReplyLayout.value = false +// hideSoftKeyboard() +// } mBinding.wvView.setTextSize(14F, isSp = true) mBinding.wvView.setAutoFitTextSize(true) mBinding.wvView.setOnItemSelectedListener(object : WheelView.OnItemSelectedListener { @@ -122,19 +121,54 @@ class ChatActivity : BaseActivity() { } } chatPageViewModel!!.scrollListToBottom.observe(this) { + Log.e("TAG", "bindView:滚动 ${it} ") if (it) { - Log.e("ChatActivity", "bindView: ${Thread.currentThread().name}") val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager val itemCount = layoutManager.itemCount - mBinding.rlvChats.scrollToPosition(itemCount - 1)//滚动到底部 + //滚动到底部 + + mBinding.rlvChats.postDelayed({ + layoutManager.scrollToPositionWithOffset( + itemCount - 1, + 0 + ) + }, 50) chatPageViewModel!!.scrollListToBottom.value = false } } - - + mBinding.llBottomLayout.visibility = View.VISIBLE + mBinding.rlBottom.visibility = View.GONE + mBinding.rlvChats.viewTreeObserver.addOnGlobalLayoutListener { + mContentHeight = mBinding.rlvChats.height + } SoftKeyBoardListener().setChangeListener(this@ChatActivity, - { _ -> Log.e("ChatActivity", "bindView: 显示") }, - { _ -> Log.e("ChatActivity", "bindView: 隐藏") }) + { h -> + mBinding.llBottomLayout.visibility = View.VISIBLE + mBinding.rlBottom.visibility = View.VISIBLE + //重置layout高度 + val layoutParams = mBinding.rlvChats.layoutParams + layoutParams.height = mContentHeight - h + mBinding.rlvChats.layoutParams = layoutParams + val layoutManager = mBinding.rlvChats.layoutManager as LinearLayoutManager + val itemCount = layoutManager.itemCount + //滚动到底部 + mBinding.rlvChats.postDelayed({ + layoutManager.scrollToPositionWithOffset( + itemCount - 1, + 0 + ) + }, 100) + + + }, + { _ -> + val layoutParams = mBinding.rlvChats.layoutParams + layoutParams.height = mContentHeight + mBinding.rlvChats.layoutParams = layoutParams + mBinding.llBottomLayout.visibility = View.VISIBLE + mBinding.rlBottom.visibility = View.GONE + + }) registerLocalReceiver() } diff --git a/app/src/main/java/com/tenlionsoft/aimz_k/page/activity/LoginActivity.kt b/app/src/main/java/com/tenlionsoft/aimz_k/page/activity/LoginActivity.kt index 6a7a5c4..aafe554 100644 --- a/app/src/main/java/com/tenlionsoft/aimz_k/page/activity/LoginActivity.kt +++ b/app/src/main/java/com/tenlionsoft/aimz_k/page/activity/LoginActivity.kt @@ -40,7 +40,13 @@ class LoginActivity : BaseActivity() { } loginPageViewModel.isLoginSuccess.observe(this) { if (it) { - startActivity(Intent(this@LoginActivity, MainActivity::class.java)) +// startActivity(Intent(this@LoginActivity, MainActivity::class.java)) + startActivity( + Intent( + this@LoginActivity, + ChatActivity::class.java + ).putExtra("fromId", "2") + ) finish() } } diff --git a/app/src/main/java/com/tenlionsoft/aimz_k/services/SocketService.kt b/app/src/main/java/com/tenlionsoft/aimz_k/services/SocketService.kt index 4d11fa6..c2acbe7 100644 --- a/app/src/main/java/com/tenlionsoft/aimz_k/services/SocketService.kt +++ b/app/src/main/java/com/tenlionsoft/aimz_k/services/SocketService.kt @@ -16,6 +16,7 @@ import com.tenlionsoft.aimz_k.socket.WsManager import com.tenlionsoft.baselib.contacts.NetConfig import com.tenlionsoft.baselib.contacts.ProjectConfig import com.tenlionsoft.baselib.utils.SpUtils +import com.tenlionsoft.baselib.utils.ToastUtils /** @@ -99,15 +100,22 @@ class SocketService : Service(), WsManager.MsgCallBack { super.onDestroy() } + //发送消息 inner class LocalReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - when (intent?.action) { - ProjectConfig.A_S_MSG_SEND -> { - val msgConvertBean = intent.getSerializableExtra("msgBean") - val msg = gson.toJson(msgConvertBean) - mWsManager?.sendMessage(msg) - }//发送消息 + val isConnect = mWsManager?.isNetworkConnected(context) + if (true == isConnect) { + when (intent?.action) { + ProjectConfig.A_S_MSG_SEND -> { + val msgConvertBean = intent.getSerializableExtra("msgBean") + val msg = gson.toJson(msgConvertBean) + mWsManager?.sendMessage(msg) + }//发送消息 + } + } else { + ToastUtils.error("请检查网络") } + } } diff --git a/app/src/main/java/com/tenlionsoft/aimz_k/socket/WsManager.kt b/app/src/main/java/com/tenlionsoft/aimz_k/socket/WsManager.kt index 322aadd..0fca234 100644 --- a/app/src/main/java/com/tenlionsoft/aimz_k/socket/WsManager.kt +++ b/app/src/main/java/com/tenlionsoft/aimz_k/socket/WsManager.kt @@ -265,7 +265,7 @@ class WsManager private constructor(val builder: Builder) : IWsManager { } //检查网络是否连接 - private fun isNetworkConnected(context: Context?): Boolean { + public fun isNetworkConnected(context: Context?): Boolean { if (context != null) { val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetwork: Network = cm.activeNetwork ?: return false diff --git a/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/ChatPageViewModel.kt b/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/ChatPageViewModel.kt index 7e988f4..e57a479 100644 --- a/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/ChatPageViewModel.kt +++ b/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/ChatPageViewModel.kt @@ -20,13 +20,20 @@ import com.tenlionsoft.aimz_k.model.MsgConvertBean import com.tenlionsoft.aimz_k.model.PickerType import com.tenlionsoft.aimz_k.model.Receiver import com.tenlionsoft.aimz_k.model.Sender +import com.tenlionsoft.aimz_k.net.UserApi import com.tenlionsoft.baselib.base.BaseViewModel import com.tenlionsoft.baselib.contacts.ProjectConfig +import com.tenlionsoft.baselib.net.RetrofitClient import com.tenlionsoft.baselib.utils.SpUtils import com.tenlionsoft.baselib.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody + class ChatPageViewModel( private val fromId: String, @@ -41,6 +48,8 @@ class ChatPageViewModel( val chooseType = MutableLiveData()//选择文件类型 val scrollListToBottom = MutableLiveData(false) private val _msgList = MutableLiveData>() + private val retrofitClient = RetrofitClient.getInstance(context) + private val netApi = retrofitClient.create(UserApi::class.java) var adapter: ChatMsgAdapter = ChatMsgAdapter(_msgList.value ?: emptyList(), this) private val mGson: Gson = Gson() @@ -121,7 +130,44 @@ class ChatPageViewModel( * 上传图片 */ fun uploadImages(list: List) { + if (list.isEmpty()) { + return + } + viewModelScope.launch { + doUploadImgs(list) + } + } + private suspend fun doUploadImgs(list: List) { + try { + for (item in list) { + if (item != null) { + val requestFile: RequestBody = + item.file!!.asRequestBody("multipart/form-data".toMediaTypeOrNull()) + val body: MultipartBody.Part = + MultipartBody.Part.createFormData( + "audio", + item.file!!.getName(), + requestFile + ) + + val bean = retrofitClient.makeApiCall { + netApi.doUploadImage(body) + } + if (bean.code == 200) { + //上传成功 + //TODO 构建消息实体 + //TODO 发送消息 + // + } else { + //TODO 上传失败 + } + } + } + + } catch (e: Exception) { + e.printStackTrace() + } } /** diff --git a/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/LoginPageViewModel.kt b/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/LoginPageViewModel.kt index 154c9b1..6b1eb5f 100644 --- a/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/LoginPageViewModel.kt +++ b/app/src/main/java/com/tenlionsoft/aimz_k/viewmodel/LoginPageViewModel.kt @@ -24,8 +24,8 @@ class LoginPageViewModel : BaseViewModel() { var userPwd: String = "admin" val isLoginSuccess = MutableLiveData() private val gson = Gson() - private val userApi = RetrofitClient.getInstance(App.context) - .create(UserApi::class.java) + private val retrofitClient = RetrofitClient.getInstance(App.context) + private val userApi = retrofitClient.create(UserApi::class.java) fun onUserNameChange(s: CharSequence, start: Int, before: Int, count: Int) { @@ -37,6 +37,7 @@ class LoginPageViewModel : BaseViewModel() { } fun doLogin() { + isLoginSuccess.value = true val isLegal = checkParams(); if (isLegal) { viewModelScope.launch { @@ -54,12 +55,16 @@ class LoginPageViewModel : BaseViewModel() { val userBody = LoginUser( userPwd, userName - ); - Log.e("LoginPageViewModel", "登陆前: Thread${Thread.currentThread().name}") + ) + val loginUserStr = gson.toJson(userBody) val body = loginUserStr.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()) - val user = userApi.doLogin(body); + + val user = retrofitClient.makeApiCall { + Log.e("TAG", "login:${Thread.currentThread().name} ") + userApi.doLogin(body) + } if (user.code == 200) { //登陆成功 val token = JwtUtils.parseToken(user.data) @@ -69,12 +74,7 @@ class LoginPageViewModel : BaseViewModel() { } else { //登陆成功 //解析Token - Log.e("LoginPageViewModel", "login: ${token}") val appTokenUser = gson.fromJson(token, AppTokenUser::class.java) - Log.e( - "LoginPageViewModel", - "Thread ${Thread.currentThread().name} login: UserId${appTokenUser.user.id}" - ) SpUtils.putPassword(userPwd) SpUtils.putAvatar(appTokenUser.user.avatar) SpUtils.putNickName(appTokenUser.user.nickname) @@ -93,7 +93,6 @@ class LoginPageViewModel : BaseViewModel() { } } catch (e: Exception) { e.printStackTrace() - Log.e("LoginPageViewModel", "login: ${e.toString()}") loginFailed() ExParse.parse(e) } diff --git a/app/src/main/res/layout/activity_chat.xml b/app/src/main/res/layout/activity_chat.xml index f52765d..4113ebf 100644 --- a/app/src/main/res/layout/activity_chat.xml +++ b/app/src/main/res/layout/activity_chat.xml @@ -11,7 +11,7 @@ type="com.tenlionsoft.aimz_k.viewmodel.ChatPageViewModel" /> - - + android:layout_weight="1" + android:background="@color/green" + tools:listitem="@layout/item_msg_my" /> - - - - - - - + android:orientation="vertical"> - - + android:minHeight="50dp" + android:orientation="horizontal" + android:paddingLeft="10dp" + android:paddingTop="5dp" + android:paddingRight="10dp" + android:paddingBottom="5dp"> - - - - - - - - - - - - - - - + android:id="@+id/iv_msg" + android:layout_width="28dp" + android:layout_height="28dp" + android:onClick="@{()->viewModel.onShowReplyLayout()}" + android:src="@drawable/ic_msg_icon" /> + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_marginLeft="10dp" + android:layout_marginRight="10dp" + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="horizontal"> - - - - - - - - - - - - - - - - - - - - + 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}" + android:textSize="14sp" /> + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/net/RetrofitClient.kt b/baselib/src/main/java/com/tenlionsoft/baselib/net/RetrofitClient.kt index ef74739..65f35b4 100644 --- a/baselib/src/main/java/com/tenlionsoft/baselib/net/RetrofitClient.kt +++ b/baselib/src/main/java/com/tenlionsoft/baselib/net/RetrofitClient.kt @@ -2,6 +2,8 @@ package com.tenlionsoft.baselib.net import android.content.Context import com.tenlionsoft.baselib.contacts.NetConfig +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory @@ -47,6 +49,12 @@ open class RetrofitClient { return builder.build(); } + suspend fun makeApiCall(apiCall: suspend () -> T): T { + return withContext(Dispatchers.IO) { + apiCall() + } + } + /** * 创建 */ diff --git a/baselib/src/main/java/com/tenlionsoft/baselib/widget/chat/ChatUiHelper.kt b/baselib/src/main/java/com/tenlionsoft/baselib/widget/chat/ChatUiHelper.kt index a3702bb..0e472d4 100644 --- a/baselib/src/main/java/com/tenlionsoft/baselib/widget/chat/ChatUiHelper.kt +++ b/baselib/src/main/java/com/tenlionsoft/baselib/widget/chat/ChatUiHelper.kt @@ -54,9 +54,9 @@ class ChatUiHelper { mEditText = editText mEditText!!.requestFocus() mEditText!!.setOnTouchListener { v: View?, event: MotionEvent -> - if (event.action == MotionEvent.ACTION_UP && mBottomLayout!!.isShown) { + if (event.action == MotionEvent.ACTION_UP) { lockContentHeight() //显示软件盘时,锁定内容高度,防止跳闪。 - hideBottomLayout(true) //隐藏表情布局,显示软件盘 +// hideBottomLayout(true) //隐藏表情布局,显示软件盘 // mIvEmoji.setImageResource(R.drawable.ic_emoji); //软件盘显示后,释放内容高度 mEditText!!.postDelayed( @@ -67,23 +67,23 @@ class ChatUiHelper { false } - mEditText!!.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { - } - - override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { - if (mEditText!!.text.toString().trim { it <= ' ' }.isNotEmpty()) { - mIvSend?.visibility = View.VISIBLE -// TODO mAddButton!!.visibility = View.GONE - } else { - mIvSend?.visibility = View.GONE -// TODO mAddButton!!.visibility = View.VISIBLE - } - } - - override fun afterTextChanged(editable: Editable) { - } - }) +// mEditText!!.addTextChangedListener(object : TextWatcher { +// override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { +// } +// +// override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { +// if (mEditText!!.text.toString().trim { it <= ' ' }.isNotEmpty()) { +// mIvSend?.visibility = View.VISIBLE +//// TODO mAddButton!!.visibility = View.GONE +// } else { +// mIvSend?.visibility = View.GONE +//// TODO mAddButton!!.visibility = View.VISIBLE +// } +// } +// +// override fun afterTextChanged(editable: Editable) { +// } +// }) return this }