feat: 新增好友免打扰功能

- 新增好友免打扰功能
- 修复好友未读消息显示错误
This commit is contained in:
糕小菜 2024-12-13 22:55:11 +08:00
parent d33e6b60c6
commit 805db56d55
17 changed files with 224 additions and 111 deletions

View File

@ -20,7 +20,7 @@ android {
minSdk = 28
targetSdk = 34
versionCode = 1
versionName = "1.0"
versionName = "0.0.01"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

View File

@ -74,7 +74,7 @@
},
{
"id": "4:6179749773128044271",
"lastPropertyId": "14:5371512009949707960",
"lastPropertyId": "15:191614052410347083",
"name": "Contact",
"properties": [
{
@ -145,8 +145,8 @@
"type": 9
},
{
"id": "14:5371512009949707960",
"name": "disturb",
"id": "15:191614052410347083",
"name": "doNotDisturb",
"type": 1
}
],
@ -200,7 +200,7 @@
},
{
"id": "6:411582187056789368",
"lastPropertyId": "12:385998119105891942",
"lastPropertyId": "14:1552912281343049591",
"name": "Conversation",
"properties": [
{
@ -250,6 +250,11 @@
"id": "11:1529665629379902832",
"name": "isPinned",
"type": 1
},
{
"id": "14:1552912281343049591",
"name": "doNotDisturb",
"type": 1
}
],
"relations": []
@ -292,7 +297,9 @@
6199737871252062125,
2020630799900991467,
385998119105891942,
8166842332862045141
8166842332862045141,
605708604168234493,
5371512009949707960
],
"retiredRelationUids": [],
"version": 1

View File

@ -5,7 +5,7 @@
"entities": [
{
"id": "1:488582047102418567",
"lastPropertyId": "15:6294917834245722650",
"lastPropertyId": "16:1385814819739404832",
"name": "Messages",
"properties": [
{
@ -44,11 +44,6 @@
"name": "senderId",
"type": 9
},
{
"id": "11:8166842332862045141",
"name": "takerId",
"type": 9
},
{
"id": "12:4851920989895940582",
"name": "show",
@ -68,6 +63,11 @@
"id": "15:6294917834245722650",
"name": "avatarUrl",
"type": 9
},
{
"id": "16:1385814819739404832",
"name": "talkerId",
"type": 9
}
],
"relations": []
@ -200,7 +200,7 @@
},
{
"id": "6:411582187056789368",
"lastPropertyId": "12:385998119105891942",
"lastPropertyId": "14:1552912281343049591",
"name": "Conversation",
"properties": [
{
@ -250,6 +250,11 @@
"id": "11:1529665629379902832",
"name": "isPinned",
"type": 1
},
{
"id": "14:1552912281343049591",
"name": "doNotDisturb",
"type": 1
}
],
"relations": []
@ -291,7 +296,9 @@
8705063061921345729,
6199737871252062125,
2020630799900991467,
385998119105891942
385998119105891942,
8166842332862045141,
605708604168234493
],
"retiredRelationUids": [],
"version": 1

View File

@ -28,5 +28,5 @@ data class Contact(
var showHeader: Boolean? = false,
var address: String? = null,
var gender: String? = null,
var disturb: Boolean = true
var doNotDisturb: Boolean = false
)

View File

@ -3,7 +3,6 @@ package com.kaixed.kchat.data.local.entity
import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id
import io.objectbox.annotation.Index
import io.objectbox.relation.ToOne
/**
* @Author: kaixed
@ -23,4 +22,5 @@ data class Conversation(
var unreadCount: Int = 0,
var isShow: Boolean = true,
var isPinned: Boolean = false,
var doNotDisturb: Boolean = false
)

View File

@ -4,6 +4,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.kaixed.kchat.data.LocalDatabase.getContactByUsername
import com.kaixed.kchat.data.local.box.ObjectBox.getBoxStore
import com.kaixed.kchat.data.local.entity.Contact
import com.kaixed.kchat.data.local.entity.Contact_
import com.kaixed.kchat.data.local.entity.Conversation
import com.kaixed.kchat.data.local.entity.Conversation_
import com.kaixed.kchat.data.local.entity.Messages
@ -23,6 +25,7 @@ object ConversationManager {
val conversations: LiveData<List<Conversation>?> get() = _conversationLiveData
private val conversationBox: Box<Conversation> by lazy { getBoxStore().boxFor() }
private val contactBox: Box<Contact> by lazy { getBoxStore().boxFor() }
private val messagesBox: Box<Messages> by lazy { getBoxStore().boxFor() }
private val conversationMap: MutableMap<String, Conversation> = mutableMapOf()
@ -39,13 +42,13 @@ object ConversationManager {
// 使用 Map 来优化查找效率
conversationMap.putAll(conversations.associateBy { it.talkerId })
_conversationLiveData.postValue(conversations.sortedByDescending { it.timestamp })
updateLiveData()
}
fun handleMessages(messages: Messages) {
val updatedConversation = updateConversation(messages)
conversationBox.put(updatedConversation)
_conversationLiveData.postValue(conversationMap.values.sortedByDescending { it.timestamp })
updateLiveData()
}
private fun updateConversation(messages: Messages): Conversation {
@ -63,14 +66,46 @@ object ConversationManager {
conversationMap[contactId]?.apply {
isShow = false
}
_conversationLiveData.postValue(conversationMap.values.filter { it.isShow }
.sortedByDescending { it.timestamp })
updateLiveData()
}
fun deleteConversation(conversation: Conversation) {
conversationMap.remove(conversation.talkerId)
conversationBox.query(Conversation_.talkerId.equal(conversation.talkerId)).build().remove()
messagesBox.query(Messages_.talkerId.equal(conversation.talkerId)).build().remove()
updateLiveData()
}
fun updateUnreadCount(talkerId: String) {
conversationMap[talkerId].apply {
this?.unreadCount = 0
}
val conversation =
conversationBox.query(Conversation_.talkerId.equal(talkerId)).build().findFirst()
conversation?.let {
it.unreadCount = 0
conversationBox.put(it)
}
updateLiveData()
}
fun updateDisturbStatus(contactId: String, isDisturb: Boolean) {
conversationMap[contactId]?.apply {
this.doNotDisturb = isDisturb
}
conversationBox.put(conversationMap[contactId]!!)
val dbContact = contactBox.query(Contact_.username.equal(contactId)).build()
.findFirst().apply {
this?.doNotDisturb = isDisturb
}
contactBox.put(dbContact!!)
updateLiveData()
}
private fun updateLiveData() {
_conversationLiveData.postValue(conversationMap.values.sortedByDescending { it.timestamp })
}

View File

@ -6,8 +6,10 @@ import androidx.activity.enableEdgeToEdge
import com.bumptech.glide.Glide
import com.kaixed.kchat.data.LocalDatabase.getContactByUsername
import com.kaixed.kchat.databinding.ActivityChatDetailBinding
import com.kaixed.kchat.manager.ConversationManager
import com.kaixed.kchat.manager.MessagesManager
import com.kaixed.kchat.ui.base.BaseActivity
import com.kaixed.kchat.ui.widget.SwitchButton
import org.greenrobot.eventbus.EventBus
class ChatDetailActivity : BaseActivity<ActivityChatDetailBinding>() {
@ -36,9 +38,16 @@ class ChatDetailActivity : BaseActivity<ActivityChatDetailBinding>() {
override fun initData() {
contactId = intent.getStringExtra("contactId") ?: ""
binding.ciSetDisturb.setSwitchChecked(contact?.doNotDisturb ?: false)
}
private fun setListener() {
binding.ciSetDisturb.sbSwitch.setOnCheckedChangeListener(object :
SwitchButton.OnCheckedChangeListener {
override fun onCheckedChanged(button: SwitchButton, isChecked: Boolean) {
ConversationManager.updateDisturbStatus(contactId, isChecked)
}
})
binding.ciCleanChatHistory.setOnClickListener {
val timestamp = System.currentTimeMillis()
MessagesManager.cleanMessages(timestamp)

View File

@ -18,6 +18,9 @@ class AboutActivity : BaseActivity<ActivityAboutBinding>() {
}
override fun initData() {
val activityInfo = packageManager.getPackageInfo(packageName, 0)
val version = "Version ${activityInfo.versionName}"
binding.tvVersion.text = version
binding.ciCheckUpdate.setOnClickListener {
val loadingDialog = LoadingDialogFragment.newInstance("检查中...")
loadingDialog.showLoading(supportFragmentManager)

View File

@ -54,13 +54,7 @@ class ConversationAdapter(
Glide.with(context).load(chatList.avatarUrl).apply(options)
.into(holder.binding.ifvAvatar)
}
if (chatList.unreadCount != 0) {
holder.binding.tvUnreadCount.text = chatList.unreadCount.toString()
holder.binding.rlUnreadCount.visibility = View.VISIBLE
} else {
holder.binding.rlUnreadCount.visibility = View.INVISIBLE
}
val bind = holder.binding
holder.bind(chatList, context)
holder.itemView.setOnClickListener {
@ -76,9 +70,30 @@ class ConversationAdapter(
onItemListener!!.onItemLongClick(chatList.talkerId, chatList.nickname)
true
}
bind.ivDoNotDisturb.visibility = if (chatList.doNotDisturb) View.VISIBLE else View.INVISIBLE
if (chatList.unreadCount == 0) {
bind.viewRedDot.visibility = View.INVISIBLE
bind.rlUnreadCount.visibility = View.INVISIBLE
return
}
inner class MyViewHolder(val binding: ChatMainItemBinding) :
if (chatList.unreadCount > 99) {
holder.binding.tvUnreadCount.text = "99+"
}
bind.viewRedDot.visibility =
if (chatList.doNotDisturb) View.VISIBLE else View.INVISIBLE
if (chatList.doNotDisturb) {
bind.rlUnreadCount.visibility = View.INVISIBLE
} else {
bind.tvUnreadCount.text = chatList.unreadCount.toString()
bind.rlUnreadCount.visibility = View.VISIBLE
}
}
class MyViewHolder(val binding: ChatMainItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(chatList: Conversation, context: Context) {
binding.tvContent.text = chatList.lastContent.replaceSpan("[委屈]") {

View File

@ -294,19 +294,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(), OnItemListener,
override fun onItemClick(talkerId: String) {
this.talkerId = talkerId
for (i in chatLists.indices) {
if (chatLists[i].talkerId == talkerId) {
chatLists[i].unreadCount = 0
}
}
notifyData()
val conversation =
conversationBox.query(Conversation_.talkerId.equal(talkerId)).build().findFirst()
conversation?.let {
it.unreadCount = 0
conversationBox.put(it)
}
ConversationManager.updateUnreadCount(talkerId)
}
private var longClickTalkerId = ""

View File

@ -24,6 +24,9 @@ class CustomItem @JvmOverloads constructor(
private var binding: ItemCustomBinding =
ItemCustomBinding.inflate(LayoutInflater.from(context), this, true)
val sbSwitch: SwitchButton
get() = binding.sbSwitch
init {
attrs?.let {
val typedArray = context.obtainStyledAttributes(it, R.styleable.CustomItem, 0, 0)

View File

@ -42,8 +42,8 @@ class LoadingDialogFragment : DialogFragment() {
// 设置对话框的大小
val params = binding.root.layoutParams
params.height = dpToPx(150)
params.width = dpToPx(150)
params.height = dpToPx(120)
params.width = dpToPx(120)
binding.root.layoutParams = params
return dialog

View File

@ -18,10 +18,15 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:layout_width="65dp"
@ -36,19 +41,20 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:text="开心聊"
android:text="kchat"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="Version 0.0.01"
android:textColor="@color/black"
android:textSize="17sp" />
android:textSize="15sp" />
<View
android:layout_width="match_parent"
@ -87,5 +93,18 @@
android:layout_marginHorizontal="30dp"
android:background="#E5E5E5" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="Copyright © 2024-Present 糕小菜. All Rights Reserved."
android:textSize="11sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.kaixed.kchat.ui.widget.ReBoundScrollView>
</LinearLayout>

View File

@ -12,8 +12,8 @@
android:id="@+id/ctb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:titleIcon="@drawable/ic_more"
android:background="#F7F7F7"
app:titleIcon="@drawable/ic_more"
app:titleName="contact" />
<androidx.recyclerview.widget.RecyclerView

View File

@ -38,6 +38,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:ellipsize="end"
android:maxWidth="45dp"
android:maxLines="1"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="@id/ifv_avatar"
app:layout_constraintStart_toStartOf="@id/ifv_avatar"
@ -54,6 +57,7 @@
app:itemName="查找聊天记录" />
<com.kaixed.kchat.ui.widget.CustomItem
android:id="@+id/ci_set_disturb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"

View File

@ -18,6 +18,18 @@
app:layout_constraintTop_toTopOf="parent"
app:roundPercent="0.3" />
<View
android:id="@+id/view_red_dot"
android:layout_width="8dp"
android:layout_height="8dp"
android:background="@drawable/icon_red_dot"
android:visibility="invisible"
app:layout_constraintCircle="@id/ifv_avatar"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="28dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<RelativeLayout
android:id="@+id/rl_unread_count"
android:layout_width="15dp"
@ -71,7 +83,7 @@
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="@id/ifv_avatar"
app:layout_constraintEnd_toEndOf="@id/tv_timestamp"
app:layout_constraintEnd_toStartOf="@id/iv_do_not_disturb"
app:layout_constraintStart_toStartOf="@id/tv_nickname"
app:layout_constraintTop_toTopOf="@id/guide" />
@ -86,5 +98,16 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_nickname" />
<ImageView
android:id="@+id/iv_do_not_disturb"
android:layout_width="12dp"
android:layout_height="12dp"
android:src="@drawable/ic_not_disturb"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@id/tv_content"
app:layout_constraintEnd_toEndOf="@id/tv_timestamp"
app:layout_constraintStart_toStartOf="@id/tv_timestamp"
app:layout_constraintTop_toTopOf="@id/tv_content" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -7,7 +7,7 @@
android:orientation="vertical"
android:paddingHorizontal="25dp"
android:paddingVertical="25dp"
app:cardCornerRadius="5dp"
app:cardCornerRadius="8dp"
app:cardElevation="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
@ -18,8 +18,8 @@
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="15dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@id/tv_loading"
@ -35,13 +35,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="15dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="@dimen/margin"
android:gravity="center_horizontal"
android:maxWidth="100dp"
android:text="正在查找联系人..."
android:textColor="@color/white"
android:textSize="17sp"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"