diff --git a/.idea/GitCommitMessageStorage.xml b/.idea/GitCommitMessageStorage.xml index 3b56900..e4fd56a 100644 --- a/.idea/GitCommitMessageStorage.xml +++ b/.idea/GitCommitMessageStorage.xml @@ -2,19 +2,7 @@ \ No newline at end of file diff --git a/app/src/main/java/com/kaixed/kchat/manager/ConversationManager.kt b/app/src/main/java/com/kaixed/kchat/manager/ConversationManager.kt index c66deb3..5aa69c4 100644 --- a/app/src/main/java/com/kaixed/kchat/manager/ConversationManager.kt +++ b/app/src/main/java/com/kaixed/kchat/manager/ConversationManager.kt @@ -30,6 +30,7 @@ object ConversationManager { private val conversationMap: MutableMap = mutableMapOf() private var unreadCount = 0 + val unReadMsgCount get() = unreadCount init { loadConversations() @@ -49,7 +50,8 @@ object ConversationManager { } fun handleMessages(messages: Messages) { - if (messages.senderId != getUsername() || messages.talkerId != getCurrentContactId()) { + val talkerId = getCurrentContactId() + if (messages.senderId != getUsername() && messages.talkerId != talkerId) { unreadCount++ } val updatedConversation = updateConversation(messages) diff --git a/app/src/main/java/com/kaixed/kchat/manager/MessagesManager.kt b/app/src/main/java/com/kaixed/kchat/manager/MessagesManager.kt index c9d167a..a3679ac 100644 --- a/app/src/main/java/com/kaixed/kchat/manager/MessagesManager.kt +++ b/app/src/main/java/com/kaixed/kchat/manager/MessagesManager.kt @@ -1,5 +1,6 @@ package com.kaixed.kchat.manager +import com.kaixed.kchat.data.DataBase import com.kaixed.kchat.data.LocalDatabase import com.kaixed.kchat.data.LocalDatabase.getAllHistoryMessages import com.kaixed.kchat.data.LocalDatabase.getMessagesWithContact @@ -25,6 +26,14 @@ object MessagesManager { private var loading = false private var tempIndex: Long = 0 + fun deleteMessage(msgLocalId: Long) { + DataBase.messagesBox.remove(msgLocalId) + val msg = _messages.value.toMutableList().apply { + removeIf { it.msgLocalId == msgLocalId } + } + _messages.value = msg + } + fun queryHistory(msgLocalId: Long): Int { _messages.value = emptyList() val msg = getAllHistoryMessages(contactId, msgLocalId) @@ -49,6 +58,7 @@ object MessagesManager { } fun receiveMessage(messages: Messages) { + if (messages.talkerId != contactId) return if (_messages.value.first() == messages) return _messages.value = _messages.value.toMutableList().apply { add(0, messages) diff --git a/app/src/main/java/com/kaixed/kchat/network/ApiCall.kt b/app/src/main/java/com/kaixed/kchat/network/ApiCall.kt index 54dcc97..cfc28d0 100644 --- a/app/src/main/java/com/kaixed/kchat/network/ApiCall.kt +++ b/app/src/main/java/com/kaixed/kchat/network/ApiCall.kt @@ -6,8 +6,7 @@ package com.kaixed.kchat.network */ object ApiCall { suspend fun apiCall( - apiCall: suspend () -> ApiResponse, - errorMessage: String = "操作失败" + apiCall: suspend () -> ApiResponse, errorMessage: String = "操作失败" ): Result { return try { val response = apiCall() diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/ChatActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/ChatActivity.kt index 75dfa6b..5314674 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/ChatActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/ChatActivity.kt @@ -28,10 +28,12 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.kaixed.kchat.R +import com.kaixed.kchat.data.event.UnreadEvent import com.kaixed.kchat.data.local.box.ObjectBox.getBoxStore import com.kaixed.kchat.data.local.entity.Messages import com.kaixed.kchat.data.model.FunctionItem import com.kaixed.kchat.databinding.ActivityChatBinding +import com.kaixed.kchat.manager.ConversationManager import com.kaixed.kchat.manager.MessagesManager import com.kaixed.kchat.processor.MessageProcessor import com.kaixed.kchat.service.WebSocketService @@ -59,6 +61,9 @@ import com.tencent.mmkv.MMKV import io.objectbox.Box import io.objectbox.kotlin.boxFor import kotlinx.coroutines.launch +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import org.json.JSONObject import java.io.File @@ -108,6 +113,7 @@ class ChatActivity : BaseActivity(), OnItemClickListener, override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() + EventBus.getDefault().register(this) firstLoadData() initView() setListener() @@ -367,6 +373,7 @@ class ChatActivity : BaseActivity(), OnItemClickListener, } private fun initView() { + binding.ctb.setUnReadCount(ConversationManager.unReadMsgCount) setupFunctionPanel() setRecycleView() contactNickname?.let { @@ -461,8 +468,15 @@ class ChatActivity : BaseActivity(), OnItemClickListener, ) } + @Subscribe(threadMode = ThreadMode.MAIN) + fun onMessageEvent(unreadEvent: UnreadEvent) { + val unreadCount = unreadEvent.unreadCount + binding.ctb.setUnReadCount(unreadCount) + } + override fun onDestroy() { super.onDestroy() + EventBus.getDefault().unregister(this) MessagesManager.resetMessages() mmkv.putString(CURRENT_CONTACT_ID, "") if (bound) { diff --git a/app/src/main/java/com/kaixed/kchat/ui/activity/setting/UpdatePasswordActivity.kt b/app/src/main/java/com/kaixed/kchat/ui/activity/setting/UpdatePasswordActivity.kt index 4637f49..a7f9bfb 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/activity/setting/UpdatePasswordActivity.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/activity/setting/UpdatePasswordActivity.kt @@ -54,9 +54,7 @@ class UpdatePasswordActivity : BaseActivity() { } else { loadingDialog.showLoading(supportFragmentManager) val updatePassword = UpdatePasswordRequest( - ConstantsUtil.getUsername(), - oldPassword, - newPassword + ConstantsUtil.getUsername(), oldPassword, newPassword ) userViewModel.updatePassword(updatePassword) } @@ -93,9 +91,8 @@ class UpdatePasswordActivity : BaseActivity() { } override fun afterTextChanged(s: Editable?) { - val enable = binding.cetNewPassword.text?.length != 0 && - binding.cetOldPassword.text?.length != 0 && - binding.cetConfirmPassword.text?.length != 0 + val enable = + binding.cetNewPassword.text?.length != 0 && binding.cetOldPassword.text?.length != 0 && binding.cetConfirmPassword.text?.length != 0 binding.titleBar.setBtnEnable(enable) } } diff --git a/app/src/main/java/com/kaixed/kchat/ui/adapter/ChatAdapter.kt b/app/src/main/java/com/kaixed/kchat/ui/adapter/ChatAdapter.kt index 9103fdc..f82a4a3 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/adapter/ChatAdapter.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/adapter/ChatAdapter.kt @@ -1,7 +1,6 @@ package com.kaixed.kchat.ui.adapter import android.content.Context -import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import android.widget.ImageView @@ -19,10 +18,10 @@ import com.kaixed.kchat.data.local.entity.Messages import com.kaixed.kchat.databinding.ChatRecycleItemCustomNormalBinding import com.kaixed.kchat.databinding.ChatRecycleItemImageNormalBinding import com.kaixed.kchat.databinding.ChatRecycleItemTipBinding +import com.kaixed.kchat.manager.MessagesManager import com.kaixed.kchat.utils.ConstantsUtil import com.kaixed.kchat.utils.ConstantsUtil.getUsername import com.kaixed.kchat.utils.PopWindowUtil.showPopupWindow -import com.kaixed.kchat.utils.TextUtil import com.kaixed.kchat.utils.TextUtil.extractDimensionsAndPrefix import com.kaixed.kchat.utils.ViewUtil.changeTimerVisibility import com.kaixed.kchat.utils.ViewUtil.setViewVisibility @@ -57,22 +56,25 @@ class ChatAdapter( return when (viewType) { CUSTOM -> { CustomViewHolder( - ChatRecycleItemCustomNormalBinding - .inflate(LayoutInflater.from(parent.context), parent, false) + ChatRecycleItemCustomNormalBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) ) } IMAGE -> { ImageViewHolder( - ChatRecycleItemImageNormalBinding - .inflate(LayoutInflater.from(parent.context), parent, false) + ChatRecycleItemImageNormalBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) ) } else -> { TipViewHolder( - ChatRecycleItemTipBinding - .inflate(LayoutInflater.from(parent.context), parent, false) + ChatRecycleItemTipBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) ) } } @@ -108,30 +110,18 @@ class ChatAdapter( } contentView?.setOnLongClickListener { - Log.d("haha", "长按了:${message.content} position: $position") val popupWindow = showPopupWindow(context, it, message.senderId == getUsername()) val deleteButton = popupWindow.contentView.findViewById(R.id.tv_delete) deleteButton.setOnClickListener { - deleteMessage(position, message) - Log.d("haha", "长按并删除了了:${message.content} position: $position") + deleteMessage(message) popupWindow.dismiss() } true } } - private fun deleteMessage(position: Int, message: Messages) { - // 从数据库删除 -// val messagesBox: Box = getBox(Messages::class.java) -// messagesBox.remove(message.msgLocalId) -// -// // 更新数据源并通知 RecyclerView -// messages.removeAt(position) -// notifyItemRemoved(position) -// -// if (position != messages.size) { // 如果移除的是最后一个,忽略 -// notifyItemRangeChanged(position, messages.size - position); -// } + private fun deleteMessage(message: Messages) { + MessagesManager.deleteMessage(message.msgLocalId) } interface HasTimer { @@ -162,8 +152,7 @@ class ChatAdapter( contentId = binding.tvMsgContent.id, contentMineId = binding.tvMsgContentMine.id ) - val avatarUrl = - if (sender) ConstantsUtil.getAvatarUrl() else message.avatarUrl + val avatarUrl = if (sender) ConstantsUtil.getAvatarUrl() else message.avatarUrl Glide.with(binding.root.context).load(avatarUrl) .into(if (sender) binding.ifvAvatarMine else binding.ifvAvatar) @@ -182,8 +171,7 @@ class ChatAdapter( RecyclerView.ViewHolder(binding.root), HasTimer { fun bindData(message: Messages) { val sender = message.senderId == getUsername() - val avatarUrl = - if (sender) ConstantsUtil.getAvatarUrl() else message.avatarUrl + val avatarUrl = if (sender) ConstantsUtil.getAvatarUrl() else message.avatarUrl Glide.with(binding.root.context).load(avatarUrl) .into(if (sender) binding.ifvAvatarMine else binding.ifvAvatar) @@ -209,8 +197,8 @@ class ChatAdapter( this.width = width } } - Glide.with(binding.root.context).load(url) - .placeholder(R.drawable.image_loading).into(imageView) + Glide.with(binding.root.context).load(url).placeholder(R.drawable.image_loading) + .into(imageView) } ?: run { Glide.with(binding.root.context).load(message.content) .placeholder(R.drawable.image_loading).into(imageView) diff --git a/app/src/main/java/com/kaixed/kchat/ui/widget/CustomTitleBar.kt b/app/src/main/java/com/kaixed/kchat/ui/widget/CustomTitleBar.kt index 12649e9..76538ed 100644 --- a/app/src/main/java/com/kaixed/kchat/ui/widget/CustomTitleBar.kt +++ b/app/src/main/java/com/kaixed/kchat/ui/widget/CustomTitleBar.kt @@ -67,8 +67,9 @@ class CustomTitleBar @JvmOverloads constructor( } } - fun setOnBackClickListener(listener: OnClickListener?) { - binding.ivBack.setOnClickListener(listener) + fun setUnReadCount(count: Int) { + binding.rlUnreadCount.visibility = if (count > 0) View.VISIBLE else View.INVISIBLE + binding.tvUnreadCount.text = count.toString() } fun setOnSettingClickListener(listener: OnClickListener?) { diff --git a/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt b/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt index 08c18c5..b714db1 100644 --- a/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/kaixed/kchat/viewmodel/UserViewModel.kt @@ -36,6 +36,7 @@ class UserViewModel : ViewModel() { viewModelScope.launch { val result = userProfileRepo.updatePassword(updatePasswordRequest) _updatePasswordResult.postValue(result) + _updatePasswordResult.value = result } } diff --git a/app/src/main/res/drawable/icon_gray_dot.xml b/app/src/main/res/drawable/icon_gray_dot.xml new file mode 100644 index 0000000..37cf55a --- /dev/null +++ b/app/src/main/res/drawable/icon_gray_dot.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/layout/view_title_bar.xml b/app/src/main/res/layout/view_title_bar.xml index f1846be..ff83ae8 100644 --- a/app/src/main/res/layout/view_title_bar.xml +++ b/app/src/main/res/layout/view_title_bar.xml @@ -14,6 +14,29 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + +