Jelajahi Sumber

feat: IM会话列表刷新问题

DoggyZhang 3 bulan lalu
induk
melakukan
4215d07f03

+ 5 - 1
app/build.gradle

@@ -123,7 +123,11 @@ android {
         buildConfigField("Integer", "TRTC_APP_ID_DEBUG", "20030346")
         buildConfigField("String", "TRTC_SECRET_KEY_DEBUG", '"a063a1a88b743dacba7f969b70e0b3aec161be06f1326a3913032c5632ed28f9"')
 
-        //sign key
+        //官方会话ID
+        buildConfigField("String", "OFFICIAL_UID", "\"${OFFICIAL_UID}\"")
+        buildConfigField("String", "OFFICIAL_CONVERSATION_ID", "\"${OFFICIAL_CONVERSATION_ID}\"")
+
+        //sign key(业务登录)
         buildConfigField("String", "SIGN_KEY", '"abc|abc|edg|9527|1234"')
         buildConfigField("String", "SIGN_KEY_DEBUG", '"abc|abc|edg|9527|1234"')
     }

+ 18 - 2
app/src/main/java/com/adealink/weparty/debug/DebugActivity.kt

@@ -12,6 +12,7 @@ import com.adealink.frame.mvvm.view.viewBinding
 import com.adealink.frame.router.Router
 import com.adealink.frame.router.annotation.RouterUri
 import com.adealink.frame.util.AppUtil
+import com.adealink.frame.util.onClick
 import com.adealink.weparty.App
 import com.adealink.weparty.commonui.BaseActivity
 import com.adealink.weparty.commonui.ext.gone
@@ -23,6 +24,7 @@ import com.adealink.weparty.databinding.ActivityDebugBinding
 import com.adealink.weparty.log.viewmodel.LogViewModelFactory
 import com.adealink.weparty.module.account.AccountLocalService
 import com.adealink.weparty.module.account.AccountModule
+import com.adealink.weparty.module.im.IMModule
 import com.adealink.weparty.storage.AppPref
 import com.adealink.weparty.util.goLocalLinkPage
 import com.google.gson.annotations.SerializedName
@@ -44,6 +46,11 @@ class DebugActivity : BaseActivity(), OnReturnValue {
         //用户/APP信息
         binding.etTestAccount.setText(AccountLocalService.testAccount)
         binding.userInfo.text = "uid: ${AppPref.uid}"
+        binding.tvImLogin.text = "IM登录状态: " + if (IMModule.isLogin()) {
+            "已登录"
+        } else {
+            "未登录"
+        }
         binding.btnSwitchAccount.setOnClickListener {
             val fbAccount = binding.etTestAccount.text.toString()
             if (fbAccount.isEmpty()) {
@@ -134,7 +141,8 @@ class DebugActivity : BaseActivity(), OnReturnValue {
             }
             isShowMemoryFloatView = isChecked
             if (isChecked) {
-                val memoryUsageFloatView = createSysMemoryUsageFloatView() ?: return@setOnCheckedChangeListener
+                val memoryUsageFloatView =
+                    createSysMemoryUsageFloatView() ?: return@setOnCheckedChangeListener
                 WindowManagerProxy.getWindowManager().addView(memoryUsageFloatView)
                 return@setOnCheckedChangeListener
             }
@@ -143,6 +151,14 @@ class DebugActivity : BaseActivity(), OnReturnValue {
                 sysMemoryUsageFloatView = null
             }
         }
+
+        binding.imSessionBtn.onClick {
+            val uid = binding.imUidEd.text?.trim()?.toString()
+            if (uid.isNullOrEmpty()) {
+                return@onClick
+            }
+            IMModule.goSession(this@DebugActivity, uid)
+        }
     }
 
     private fun saveWebUrlEd() {
@@ -196,7 +212,7 @@ class DebugActivity : BaseActivity(), OnReturnValue {
             return
         }
 
-        goLocalLinkPage(context = this,webTestUrl)
+        goLocalLinkPage(context = this, webTestUrl)
     }
 
     private fun addWhiteHost() {

+ 3 - 0
app/src/main/java/com/adealink/weparty/module/im/IIMService.kt

@@ -5,5 +5,8 @@ import com.adealink.frame.startup.IAppStartUpTask
 import com.adealink.weparty.aab.IService
 
 interface IIMService : IService<IIMService>, IAppStartUpTask {
+
+    fun isLogin(): Boolean
+
     fun goSession(activity: Activity, uid: String)
 }

+ 8 - 0
app/src/main/java/com/adealink/weparty/module/im/IMModule.kt

@@ -34,6 +34,10 @@ object IMModule : BaseDynamicModule<IIMService>(IIMService::class), IIMService {
             override fun logout() {
             }
 
+            override fun isLogin(): Boolean {
+                return false
+            }
+
             override fun goSession(activity: Activity, uid: String) {
             }
         }
@@ -59,6 +63,10 @@ object IMModule : BaseDynamicModule<IIMService>(IIMService::class), IIMService {
         getService().logout()
     }
 
+    override fun isLogin(): Boolean {
+        return getService().isLogin()
+    }
+
     override fun goSession(activity: Activity, uid: String) {
         getService().goSession(activity, uid)
     }

+ 31 - 0
app/src/main/res/layout/activity_debug.xml

@@ -383,6 +383,37 @@
 
                 </androidx.constraintlayout.widget.ConstraintLayout>
 
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="@color/color_FFE1E3E6" />
+
+                <androidx.appcompat.widget.LinearLayoutCompat
+                    android:id="@+id/im_test_cl"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <androidx.appcompat.widget.AppCompatEditText
+                        android:id="@+id/im_uid_ed"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center_vertical"
+                        android:layout_weight="1"
+                        android:hint="对方UID"
+                        android:textColor="@color/black"
+                        android:textColorHint="@color/color_333333"
+                        android:textSize="14sp" />
+
+                    <androidx.appcompat.widget.AppCompatButton
+                        android:id="@+id/im_session_btn"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center_vertical"
+                        android:gravity="center"
+                        android:text="开启会话" />
+
+                </androidx.appcompat.widget.LinearLayoutCompat>
 
                 <View
                     android:layout_width="match_parent"

+ 1 - 1
frame/tuikit/TUIChat/tuichat/src/main/java/com/tencent/qcloud/tuikit/tuichat/config/GeneralConfig.java

@@ -17,7 +17,7 @@ public class GeneralConfig {
     private boolean excludedFromUnreadCount;
     private boolean excludedFromLastMessage;
     private boolean enableAndroidPrivateRing;
-    private boolean msgNeedReadReceipt = false;
+    private boolean msgNeedReadReceipt = true;
     private boolean enableGroupChatPinMessage = true;
     private boolean enableFloatWindowForCall = true;
     private boolean enableMultiDeviceForCall = false;

+ 4 - 0
frame/tuikit/TUIConversation/tuiconversation/build.gradle

@@ -16,6 +16,10 @@ android {
             abiFilters "armeabi-v7a"
             abiFilters "arm64-v8a"
         }
+
+        //官方会话ID
+        buildConfigField("String", "OFFICIAL_UID", "\"${OFFICIAL_UID}\"")
+        buildConfigField("String", "OFFICIAL_CONVERSATION_ID", "\"${OFFICIAL_CONVERSATION_ID}\"")
     }
 
     buildTypes {

+ 3 - 1
frame/tuikit/TUIConversation/tuiconversation/src/main/java/com/tencent/qcloud/tuikit/tuiconversation/bean/ConversationInfo.java

@@ -1,11 +1,13 @@
 package com.tencent.qcloud.tuikit.tuiconversation.bean;
 
 import androidx.annotation.NonNull;
+
 import com.tencent.imsdk.v2.V2TIMConversation;
 import com.tencent.imsdk.v2.V2TIMGroupAtInfo;
 import com.tencent.imsdk.v2.V2TIMMessage;
 import com.tencent.imsdk.v2.V2TIMUserStatus;
 import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean;
+import com.tencent.qcloud.tuikit.tuiconversation.BuildConfig;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -171,7 +173,7 @@ public class ConversationInfo implements Serializable, Comparable<ConversationIn
     }
 
     public boolean isTop() {
-        return top;
+        return top || BuildConfig.OFFICIAL_CONVERSATION_ID.equals(conversationId);
     }
 
     public void setTop(boolean top) {

+ 4 - 1
gradle.properties

@@ -30,4 +30,7 @@ OFFICIAL=false
 IS_RELEASE=true
 
 VERSION_CODE=45
-VERSION_NAME=1.10.1
+VERSION_NAME=1.10.1
+
+OFFICIAL_UID=10000
+OFFICIAL_CONVERSATION_ID=c2c_10000

+ 7 - 0
module/im/src/main/java/com/adealink/weparty/im/IMServiceImpl.kt

@@ -32,6 +32,9 @@ class IMServiceImpl : IIMService {
             CustomMessageViewHolder::class.java
         )
 
+        //开启已读回执
+        TUIChatConfigs.getGeneralConfig().setMsgNeedReadReceipt(true)
+
         imLoginManager.init(application)
         TIMAppService().init(application)
     }
@@ -47,6 +50,10 @@ class IMServiceImpl : IIMService {
 
     }
 
+    override fun isLogin(): Boolean {
+        return imLoginManager.isLogin()
+    }
+
     override fun goSession(activity: Activity, uid: String) {
         val chatInfo = ChatInfo()
         chatInfo.type = ChatInfo.TYPE_C2C

+ 4 - 2
module/im/src/main/java/com/adealink/weparty/im/constant/Data.kt

@@ -1,10 +1,12 @@
 package com.adealink.weparty.im.constant
 
+import com.adealink.weparty.BuildConfig
+
 /**
  * 官方用户ID
  */
-const val OFFICIAL_UID = "10000" //官方uid
-const val OFFICIAL_CONVERSATION_ID = "c2c_${OFFICIAL_UID}"
+const val OFFICIAL_UID = BuildConfig.OFFICIAL_UID //官方uid
+const val OFFICIAL_CONVERSATION_ID = BuildConfig.OFFICIAL_CONVERSATION_ID //官方会话ID
 
 
 /**

+ 5 - 9
module/im/src/main/java/com/adealink/weparty/im/list/SessionListFragment.kt

@@ -5,7 +5,6 @@ import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
 import android.view.View
-import androidx.fragment.app.viewModels
 import androidx.localbroadcastmanager.content.LocalBroadcastManager
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
@@ -25,8 +24,6 @@ import com.adealink.weparty.im.databinding.FragmentSessionListBinding
 import com.adealink.weparty.im.list.adapter.SessionListAdapter
 import com.adealink.weparty.im.list.adapter.viewbinder.OfficialListItemViewBinder
 import com.adealink.weparty.im.list.adapter.viewbinder.SessionListItemViewBinder
-import com.adealink.weparty.im.list.viewmodel.SessionListViewModel
-import com.adealink.weparty.im.viewmodel.IMViewModelFactory
 import com.adealink.weparty.module.im.IM
 import com.tencent.imsdk.v2.V2TIMConversation
 import com.tencent.qcloud.tuicore.TUIConstants
@@ -44,8 +41,6 @@ class SessionListFragment : BaseFragment(R.layout.fragment_session_list),
     OnConversationAdapterListener {
 
     private val binding by viewBinding(FragmentSessionListBinding::bind)
-
-    private val viewModel by viewModels<SessionListViewModel> { IMViewModelFactory() }
     private val presenter: ConversationPresenter by fastLazy { ConversationPresenter() }
     private val sessionAdapter: SessionListAdapter by fastLazy { SessionListAdapter() }
     private lateinit var unreadCountReceiver: BroadcastReceiver
@@ -71,6 +66,7 @@ class SessionListFragment : BaseFragment(R.layout.fragment_session_list),
 
         sessionAdapter.register(OfficialListItemViewBinder(this))
         sessionAdapter.register(SessionListItemViewBinder(this))
+        sessionAdapter.mOnConversationAdapterListener = this
 
         presenter.setAdapter(sessionAdapter)
         presenter.setConversationListener()
@@ -118,7 +114,6 @@ class SessionListFragment : BaseFragment(R.layout.fragment_session_list),
         conversationInfo: ConversationInfo?
     ) {
         conversationInfo ?: return
-        // TODO: 测试阶段官方消息 userID为空
         if (conversationInfo.conversation?.userID == OFFICIAL_UID) {
             goOfficialSession(conversationInfo)
             return
@@ -161,24 +156,24 @@ class SessionListFragment : BaseFragment(R.layout.fragment_session_list),
     }
 
     override fun onConversationChanged(dataSource: List<ConversationInfo?>?) {
-
     }
 
+    //标记为"未读"(无此功能)
     override fun onMarkConversationUnread(
         view: View?,
         conversationInfo: ConversationInfo?,
         markUnread: Boolean
     ) {
-
     }
 
+    //标记为"隐藏"(无此功能)
     override fun onMarkConversationHidden(
         view: View?,
         conversationInfo: ConversationInfo?
     ) {
-
     }
 
+    //点击更多(无此功能)
     override fun onClickMoreView(
         view: View?,
         conversationInfo: ConversationInfo?
@@ -186,6 +181,7 @@ class SessionListFragment : BaseFragment(R.layout.fragment_session_list),
 
     }
 
+    //滑动(无此功能)
     override fun onSwipeConversationChanged(conversationInfo: ConversationInfo?) {
 
     }

+ 31 - 12
module/im/src/main/java/com/adealink/weparty/im/list/adapter/SessionListAdapter.kt

@@ -17,22 +17,25 @@ class SessionListAdapter : ExtMultiTypeAdapter(), IConversationListAdapter {
     private var mIsLoading = false
     var mOnConversationAdapterListener: OnConversationAdapterListener? = null
 
+    private var conversationList = listOf<ConversationInfo>()
+
     override fun onLoadingStateChanged(isLoading: Boolean) {
         this.mIsLoading = isLoading
         notifyItemChanged(itemCount - 1)
     }
 
     override fun onDataSourceChanged(conversationInfoList: List<ConversationInfo?>?) {
+        val newList = conversationInfoList?.mapNotNull { it } ?: emptyList()
+
+        conversationList = newList
         val itemList = mutableListOf<SessionListItemData>()
         var officialConversation: ConversationInfo? = null
-        conversationInfoList?.forEach {
-            if (it != null) {
-                if (it.conversation.conversationID == OFFICIAL_CONVERSATION_ID) {
-                    officialConversation = it
-                    itemList.add(0, OfficialSessionListItem(it))
-                } else {
-                    itemList.add(CommonSessionListItemData(it))
-                }
+        for (info in newList) {
+            if (info.conversation.conversationID == OFFICIAL_CONVERSATION_ID) {
+                officialConversation = info
+                itemList.add(0, OfficialSessionListItem(info))
+            } else {
+                itemList.add(CommonSessionListItemData(info))
             }
         }
         if (officialConversation == null) {
@@ -48,19 +51,35 @@ class SessionListAdapter : ExtMultiTypeAdapter(), IConversationListAdapter {
     }
 
     override fun onItemRemoved(position: Int) {
-        notifyItemRemoved(position)
+        if (conversationList.firstOrNull()?.conversationId == OFFICIAL_CONVERSATION_ID) {
+            notifyItemRemoved(position)
+        } else {
+            notifyItemRemoved(position + 1)
+        }
     }
 
     override fun onItemInserted(position: Int) {
-        notifyItemInserted(position)
+        if (conversationList.firstOrNull()?.conversationId == OFFICIAL_CONVERSATION_ID) {
+            notifyItemInserted(position)
+        } else {
+            notifyItemInserted(position + 1)
+        }
     }
 
     override fun onItemChanged(position: Int) {
-        notifyItemChanged(position)
+        if (conversationList.firstOrNull()?.conversationId == OFFICIAL_CONVERSATION_ID) {
+            notifyItemChanged(position)
+        } else {
+            notifyItemChanged(position + 1)
+        }
     }
 
     override fun onItemRangeChanged(startPosition: Int, count: Int) {
-        notifyItemRangeChanged(startPosition, count)
+        if (conversationList.firstOrNull()?.conversationId == OFFICIAL_CONVERSATION_ID) {
+            notifyItemRangeChanged(startPosition, count)
+        } else {
+            notifyItemRangeChanged(startPosition + 1, count)
+        }
     }
 
     override fun onConversationChanged(conversationInfoList: List<ConversationInfo?>?) {

+ 11 - 7
module/im/src/main/java/com/adealink/weparty/im/list/adapter/viewbinder/SessionListItemViewBinder.kt

@@ -2,8 +2,10 @@ package com.adealink.weparty.im.list.adapter.viewbinder
 
 import android.view.LayoutInflater
 import android.view.ViewGroup
+import com.adealink.frame.base.AppBase
 import com.adealink.frame.data.json.froJsonErrorNull
 import com.adealink.frame.dot.NumDot
+import com.adealink.frame.log.Log
 import com.adealink.frame.util.onClick
 import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
 import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
@@ -24,21 +26,23 @@ class SessionListItemViewBinder(
         holder: BindingViewHolder<LayoutSessionListItemBinding>,
         item: CommonSessionListItemData,
     ) {
+        Log.d("zhangfei", "onBindViewHolder, position:${holder.layoutPosition}, item:${item}")
         holder.binding.root.onClick {
             listener.onItemClick(it, item.data.type, item.data)
         }
-
-        // TODO: 长按测试用
-        holder.binding.root.setOnLongClickListener {
-            listener.onItemLongClick(it, item.data)
-            true
-        }
-
         holder.binding.ivAvatar.onClick {
 
         }
         holder.binding.tvTitle.text = item.data.title
         setLastMessageAndStatus(holder, item)
+
+        // TODO: 长按测试用
+        if (!AppBase.isRelease) {
+            holder.binding.root.setOnLongClickListener {
+                listener.onItemLongClick(it, item.data)
+                true
+            }
+        }
     }
 
     private fun setLastMessageAndStatus(

+ 8 - 1
module/im/src/main/java/com/adealink/weparty/im/list/viewmodel/SessionListViewModel.kt

@@ -1,11 +1,18 @@
 package com.adealink.weparty.im.list.viewmodel
 
+import com.adealink.frame.base.fastLazy
 import com.adealink.frame.mvvm.viewmodel.BaseViewModel
+import com.tencent.qcloud.tuikit.tuiconversation.presenter.ConversationPresenter
+import kotlinx.coroutines.launch
 
 class SessionListViewModel : BaseViewModel() {
 
-    fun clearMessage() {
+    private val presenter: ConversationPresenter by fastLazy { ConversationPresenter() }
 
+    fun clearMessage() {
+        viewModelScope.launch {
+            presenter.clearAllUnreadMessage()
+        }
     }
 
 }

+ 2 - 2
module/im/src/main/java/com/adealink/weparty/im/session/adapter/viewbinder/BaseMessageViewBinder.kt

@@ -62,7 +62,7 @@ abstract class BaseMessageViewBinder<T : TUIMessageBean, V : ViewBinding, MH : M
     }
 
     private fun applySelfStyle(holder: MH, msg: T) {
-        holder.binding.messageContent.gravity = Gravity.END
+        holder.binding.llContent.gravity = Gravity.END
         holder.messageBinding.root.setBackgroundResource(R.drawable.im_message_bubble_self_bg)
         holder.messageBinding.root.setPaddingRelative(
             getCompatDimension(R.dimen.im_message_bubble_self_padding_start).toInt(),
@@ -77,7 +77,7 @@ abstract class BaseMessageViewBinder<T : TUIMessageBean, V : ViewBinding, MH : M
     }
 
     private fun applyOtherStyle(holder: MH, msg: T) {
-        holder.binding.messageContent.gravity = Gravity.START
+        holder.binding.llContent.gravity = Gravity.START
         holder.messageBinding.root.setBackgroundResource(R.drawable.im_message_bubble_other_bg)
         holder.messageBinding.root.setPaddingRelative(
             getCompatDimension(R.dimen.im_message_bubble_other_padding_start).toInt(),

+ 27 - 16
module/im/src/main/res/layout/layout_session_message_base.xml

@@ -25,29 +25,40 @@
         tools:text="11/20"
         tools:visibility="visible" />
 
-    <androidx.appcompat.widget.AppCompatImageView
-        android:id="@+id/iv_message_status"
-        android:layout_width="16dp"
-        android:layout_height="16dp"
-        android:layout_marginEnd="4dp"
-        android:visibility="gone"
-        app:layout_constraintBottom_toBottomOf="@id/message_content"
-        app:layout_constraintEnd_toStartOf="@id/message_content"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@id/message_content"
-        app:srcCompat="@drawable/session_send_error_ic"
-        tools:visibility="visible" />
-
     <androidx.appcompat.widget.LinearLayoutCompat
-        android:id="@+id/message_content"
+        android:id="@+id/ll_content"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginHorizontal="16dp"
         android:layout_marginTop="10dp"
         android:orientation="horizontal"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@id/iv_message_status"
+        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/tv_time"
-        app:layout_goneMarginTop="0dp" />
+        app:layout_goneMarginTop="0dp"
+        tools:gravity="end">
+
+        <androidx.appcompat.widget.AppCompatImageView
+            android:id="@+id/iv_message_status"
+            android:layout_width="16dp"
+            android:layout_height="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="4dp"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="@id/message_content"
+            app:layout_constraintEnd_toStartOf="@id/message_content"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@id/message_content"
+            app:srcCompat="@drawable/session_send_error_ic"
+            tools:visibility="visible" />
+
+        <FrameLayout
+            android:id="@+id/message_content"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            tools:layout_height="200dp"
+            tools:layout_width="200dp" />
+
+    </androidx.appcompat.widget.LinearLayoutCompat>
 
 </androidx.constraintlayout.widget.ConstraintLayout>