Sfoglia il codice sorgente

feat: 完成关注,粉丝列表

DoggyZhang 3 mesi fa
parent
commit
f1f037b261
23 ha cambiato i file con 586 aggiunte e 253 eliminazioni
  1. 2 2
      app/src/main/java/com/adealink/weparty/module/profile/data/FollowData.kt
  2. 1 2
      module/profile/src/main/java/com/adealink/weparty/profile/comp/ProfileBottomComp.kt
  3. 4 4
      module/profile/src/main/java/com/adealink/weparty/profile/datasource/remote/FollowHttpService.kt
  4. 2 11
      module/profile/src/main/java/com/adealink/weparty/profile/me/MeFragment.kt
  5. 9 5
      module/profile/src/main/java/com/adealink/weparty/profile/me/comp/MeHeaderComp.kt
  6. 127 0
      module/profile/src/main/java/com/adealink/weparty/profile/relation/FansFragment.kt
  7. 130 0
      module/profile/src/main/java/com/adealink/weparty/profile/relation/FollowFragment.kt
  8. 79 6
      module/profile/src/main/java/com/adealink/weparty/profile/relation/RelationShipActivity.kt
  9. 30 8
      module/profile/src/main/java/com/adealink/weparty/profile/relation/adapter/FansItemViewBinder.kt
  10. 48 6
      module/profile/src/main/java/com/adealink/weparty/profile/relation/adapter/FollowItemViewBinder.kt
  11. 36 11
      module/profile/src/main/java/com/adealink/weparty/profile/relation/data/RelationShipData.kt
  12. 66 16
      module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/FollowViewModel.kt
  13. 2 2
      module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/RelationShipTab.kt
  14. 0 71
      module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/fans/FansFragment.kt
  15. 0 75
      module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/follow/FollowFragment.kt
  16. 1 1
      module/profile/src/main/java/com/adealink/weparty/profile/search/adapter/SearchItemViewBinder.kt
  17. 0 0
      module/profile/src/main/res/drawable/profile_followed_button_bg.xml
  18. 13 5
      module/profile/src/main/res/layout/activity_profile_relationship.xml
  19. 13 1
      module/profile/src/main/res/layout/fragment_fans.xml
  20. 13 1
      module/profile/src/main/res/layout/fragment_follow.xml
  21. 3 22
      module/profile/src/main/res/layout/item_relationship_fans.xml
  22. 5 4
      module/profile/src/main/res/layout/item_relationship_follow.xml
  23. 2 0
      module/profile/src/main/res/values/strings.xml

+ 2 - 2
app/src/main/java/com/adealink/weparty/module/profile/data/FollowData.kt

@@ -4,7 +4,7 @@ enum class FollowStatus(val status: Int) {
     NONE(0b00), //无关注
     FOLLOW(0b01), //关注(我关注了ta)
     FANS(0b10), //粉丝(ta关注了我)
-    MUTUAL_FOLLOW(0b11); //互相关注
+    EACH_FOLLOW(0b11); //互相关注
 
     companion object {
         @JvmStatic
@@ -16,5 +16,5 @@ enum class FollowStatus(val status: Int) {
 }
 
 fun FollowStatus?.isFollowed(): Boolean {
-    return this == FollowStatus.FOLLOW || this == FollowStatus.MUTUAL_FOLLOW
+    return this == FollowStatus.FOLLOW || this == FollowStatus.EACH_FOLLOW
 }

+ 1 - 2
module/profile/src/main/java/com/adealink/weparty/profile/comp/ProfileBottomComp.kt

@@ -11,7 +11,6 @@ import com.adealink.weparty.module.profile.data.FollowStatus
 import com.adealink.weparty.profile.databinding.LayoutProfileBottomBinding
 import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
 import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
-import kotlin.getValue
 
 class ProfileBottomComp(
     lifecycleOwner: LifecycleOwner,
@@ -45,7 +44,7 @@ class ProfileBottomComp(
                 binding.btnFollow.show()
             }
 
-            FollowStatus.MUTUAL_FOLLOW,
+            FollowStatus.EACH_FOLLOW,
             FollowStatus.FOLLOW -> {
                 //互关,已经关注对方
                 binding.btnFollow.gone()

+ 4 - 4
module/profile/src/main/java/com/adealink/weparty/profile/datasource/remote/FollowHttpService.kt

@@ -3,7 +3,7 @@ package com.adealink.weparty.profile.datasource.remote
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.network.data.Res
 import com.adealink.weparty.profile.relation.data.FansListReq
-import com.adealink.weparty.profile.relation.data.FansLlistRes
+import com.adealink.weparty.profile.relation.data.FansListRes
 import com.adealink.weparty.profile.relation.data.FollowListReq
 import com.adealink.weparty.profile.relation.data.FollowListRes
 import com.adealink.weparty.profile.relation.data.FollowReq
@@ -26,16 +26,16 @@ interface FollowHttpService {
     ): Rlt<Res<Any>>
 
 
-    @POST("user/my/info/edit")
+    @POST("user/relateion/myFollows")
     suspend fun pullFollow(
         @Body req: FollowListReq
     ): Rlt<Res<FollowListRes>>
 
 
-    @POST("user/my/info/edit")
+    @POST("user/relateion/fans")
     suspend fun pullFans(
         @Body req: FansListReq
-    ): Rlt<Res<FansLlistRes>>
+    ): Rlt<Res<FansListRes>>
 
 
 }

+ 2 - 11
module/profile/src/main/java/com/adealink/weparty/profile/me/MeFragment.kt

@@ -2,7 +2,7 @@ package com.adealink.weparty.profile.me
 
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.updateLayoutParams
-import androidx.fragment.app.viewModels
+import androidx.fragment.app.activityViewModels
 import com.adealink.frame.aab.util.getCompatDimension
 import com.adealink.frame.mvvm.view.viewBinding
 import com.adealink.frame.router.annotation.RouterUri
@@ -17,7 +17,6 @@ import com.adealink.weparty.profile.me.comp.MeFunctionCenterComp
 import com.adealink.weparty.profile.me.comp.MeHeaderComp
 import com.adealink.weparty.profile.me.comp.MeShareComp
 import com.adealink.weparty.profile.me.comp.MeWalletComp
-import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
 import com.adealink.weparty.profile.viewmodel.ProfileViewModel
 import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
 import com.adealink.weparty.R as APP_R
@@ -26,8 +25,7 @@ import com.adealink.weparty.R as APP_R
 class MeFragment : BaseFragment(R.layout.fragment_me) {
 
     private val binding by viewBinding(FragmentMeBinding::bind)
-    private val profileViewModel by viewModels<ProfileViewModel> { ProfileViewModelFactory() }
-    private val followViewModel by viewModels<FollowViewModel> { ProfileViewModelFactory() }
+    private val profileViewModel by activityViewModels<ProfileViewModel> { ProfileViewModelFactory() }
 
     override fun initViews() {
         super.initViews()
@@ -45,13 +43,6 @@ class MeFragment : BaseFragment(R.layout.fragment_me) {
     override fun onResume() {
         super.onResume()
         profileViewModel.pullUserInfoBy(ProfileModule.getMyUid(), false)
-        // TODO: 刷新关注人数
-        followViewModel
-    }
-
-    override fun observeViewModel() {
-        super.observeViewModel()
-
     }
 
     override fun initComponents() {

+ 9 - 5
module/profile/src/main/java/com/adealink/weparty/profile/me/comp/MeHeaderComp.kt

@@ -3,7 +3,7 @@ package com.adealink.weparty.profile.me.comp
 import androidx.lifecycle.LifecycleOwner
 import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.mvvm.view.ViewComponent
-import com.adealink.frame.mvvm.viewmodel.viewModels
+import com.adealink.frame.mvvm.viewmodel.activityViewModels
 import com.adealink.frame.router.Router
 import com.adealink.frame.util.copyToClipBoard
 import com.adealink.frame.util.onClick
@@ -13,6 +13,7 @@ import com.adealink.weparty.module.profile.ProfileModule
 import com.adealink.weparty.module.profile.data.UserInfo
 import com.adealink.weparty.profile.R
 import com.adealink.weparty.profile.databinding.LayoutMeHeaderBinding
+import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
 import com.adealink.weparty.profile.relation.viewmodel.RelationShipTab
 import com.adealink.weparty.profile.viewmodel.ProfileViewModel
 import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
@@ -22,10 +23,8 @@ class MeHeaderComp(
     val binding: LayoutMeHeaderBinding
 ) : ViewComponent(lifecycleOwner) {
 
-    private val profileViewModel by viewModels<ProfileViewModel>(
-        ownerProducer = { viewModelStoreOwner },
-        factoryProducer = { ProfileViewModelFactory() }
-    )
+    private val profileViewModel by activityViewModels<ProfileViewModel> { ProfileViewModelFactory() }
+    private val followViewModel by activityViewModels<FollowViewModel> { ProfileViewModelFactory() }
 
     override fun onCreate() {
         super.onCreate()
@@ -54,6 +53,11 @@ class MeHeaderComp(
         binding.clFans.onClick {
             goFansList()
         }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        updateHeader(ProfileModule.getMyUserInfo())
 
     }
 

+ 127 - 0
module/profile/src/main/java/com/adealink/weparty/profile/relation/FansFragment.kt

@@ -0,0 +1,127 @@
+package com.adealink.weparty.profile.relation
+
+import androidx.fragment.app.activityViewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.base.fastLazy
+import com.adealink.frame.mvvm.view.viewBinding
+import com.adealink.frame.router.Router
+import com.adealink.weparty.commonui.BaseFragment
+import com.adealink.weparty.commonui.ext.dp
+import com.adealink.weparty.commonui.ext.gone
+import com.adealink.weparty.commonui.ext.show
+import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
+import com.adealink.weparty.commonui.recycleview.itemdecoration.VerticalSpaceItemDecoration
+import com.adealink.weparty.commonui.toast.util.showFailedToast
+import com.adealink.weparty.module.profile.Profile
+import com.adealink.weparty.profile.R
+import com.adealink.weparty.profile.databinding.FragmentFansBinding
+import com.adealink.weparty.profile.relation.adapter.FansItemViewBinder
+import com.adealink.weparty.profile.relation.data.FansItemData
+import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
+import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
+import com.scwang.smart.refresh.layout.api.RefreshLayout
+import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
+import com.adealink.weparty.R as APP_R
+
+class FansFragment : BaseFragment(R.layout.fragment_fans), FansItemViewBinder.OnFansItemClick {
+    private val binding by viewBinding(FragmentFansBinding::bind)
+    private val viewModel by activityViewModels<FollowViewModel> { ProfileViewModelFactory() }
+    private val listAdapter by fastLazy { MultiTypeListAdapter<FansItemData>() }
+    override fun initViews() {
+        super.initViews()
+        binding.vRefresh.setEnableRefresh(true)
+        binding.vRefresh.setEnableLoadMore(true)
+        binding.vRefresh.setEnableAutoLoadMore(true)
+        binding.vRefresh.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
+            override fun onRefresh(refreshLayout: RefreshLayout) {
+                viewModel.pullFollowList()
+            }
+
+
+            override fun onLoadMore(refreshLayout: RefreshLayout) {
+                viewModel.loadMoreFollowList()
+            }
+        })
+
+        listAdapter.register(FansItemViewBinder(this))
+        binding.rvFans.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+        binding.rvFans.adapter = listAdapter
+        binding.rvFans.addItemDecoration(
+            VerticalSpaceItemDecoration(
+                20.dp(),
+                firstSpaceHeight = 16.dp()
+            )
+        )
+    }
+
+    override fun loadData() {
+        super.loadData()
+        viewModel.pullFansList()
+    }
+
+    override fun observeViewModel() {
+        super.observeViewModel()
+        viewModel.fansListLD.observe(viewLifecycleOwner) {
+            listAdapter.submitList(it)
+            if (it.isNullOrEmpty()) {
+                binding.rvFans.gone()
+                binding.vErrorView.show(
+                    errorEmptyResId = APP_R.drawable.common_list_empty_ic,
+                    title = APP_R.string.commonui_list_empty
+                )
+            } else {
+                binding.rvFans.show()
+                binding.vErrorView.gone()
+            }
+        }
+        viewModel.fansListRltLD.observe(viewLifecycleOwner) { rlt ->
+            binding.vRefresh.finishRefresh()
+            binding.vRefresh.finishLoadMore()
+            showFailedToast(rlt)
+        }
+    }
+
+    override fun follow(item: FansItemData, position: Int) {
+        if (item.data.uid.isEmpty()) {
+            return
+        }
+        viewModel.follow(item.data.uid).observe(viewLifecycleOwner) { rlt ->
+            when (rlt) {
+                is Rlt.Success -> {
+                    listAdapter.notifyItemChanged(position)
+                }
+
+                is Rlt.Failed -> {
+                    showFailedToast(rlt)
+                }
+            }
+        }
+    }
+
+    override fun unFollow(item: FansItemData, position: Int) {
+        if (item.data.uid.isEmpty()) {
+            return
+        }
+        viewModel.unFollow(item.data.uid).observe(viewLifecycleOwner) { rlt ->
+            when (rlt) {
+                is Rlt.Success -> {
+                    listAdapter.notifyItemChanged(position)
+                }
+
+                is Rlt.Failed -> {
+                    showFailedToast(rlt)
+                }
+            }
+        }
+    }
+
+    override fun goProfile(uid: String) {
+        val act = activity ?: return
+        Router.build(act, Profile.UserProfile.PATH)
+            .putExtra(Profile.Common.EXTRA_UID, uid)
+            .start()
+    }
+
+}

+ 130 - 0
module/profile/src/main/java/com/adealink/weparty/profile/relation/FollowFragment.kt

@@ -0,0 +1,130 @@
+package com.adealink.weparty.profile.relation
+
+import androidx.fragment.app.activityViewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.adealink.frame.base.Rlt
+import com.adealink.frame.base.fastLazy
+import com.adealink.frame.mvvm.view.viewBinding
+import com.adealink.frame.router.Router
+import com.adealink.weparty.commonui.BaseFragment
+import com.adealink.weparty.commonui.ext.dp
+import com.adealink.weparty.commonui.ext.gone
+import com.adealink.weparty.commonui.ext.show
+import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
+import com.adealink.weparty.commonui.recycleview.itemdecoration.VerticalSpaceItemDecoration
+import com.adealink.weparty.commonui.toast.util.showFailedToast
+import com.adealink.weparty.module.profile.Profile
+import com.adealink.weparty.profile.R
+import com.adealink.weparty.profile.databinding.FragmentFollowBinding
+import com.adealink.weparty.profile.relation.adapter.FollowItemViewBinder
+import com.adealink.weparty.profile.relation.data.FollowItemData
+import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
+import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
+import com.scwang.smart.refresh.layout.api.RefreshLayout
+import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener
+import com.adealink.weparty.R as APP_R
+
+class FollowFragment : BaseFragment(R.layout.fragment_follow),
+    FollowItemViewBinder.OnFollowItemClick {
+
+    private val binding by viewBinding(FragmentFollowBinding::bind)
+    private val viewModel by activityViewModels<FollowViewModel> { ProfileViewModelFactory() }
+    private val listAdapter by fastLazy { MultiTypeListAdapter<FollowItemData>() }
+
+    override fun initViews() {
+        super.initViews()
+        binding.vRefresh.setEnableRefresh(true)
+        binding.vRefresh.setEnableLoadMore(true)
+        binding.vRefresh.setEnableAutoLoadMore(true)
+        binding.vRefresh.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener {
+            override fun onRefresh(refreshLayout: RefreshLayout) {
+                viewModel.pullFollowList()
+            }
+
+
+            override fun onLoadMore(refreshLayout: RefreshLayout) {
+                viewModel.loadMoreFollowList()
+            }
+        })
+
+        listAdapter.register(FollowItemViewBinder(this))
+        binding.rvFollow.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
+        binding.rvFollow.adapter = listAdapter
+        binding.rvFollow.addItemDecoration(
+            VerticalSpaceItemDecoration(
+                20.dp(),
+                firstSpaceHeight = 16.dp()
+            )
+        )
+    }
+
+    override fun loadData() {
+        super.loadData()
+        viewModel.pullFollowList()
+    }
+
+    override fun observeViewModel() {
+        super.observeViewModel()
+        viewModel.followListLD.observe(viewLifecycleOwner) {
+            listAdapter.submitList(it)
+            if (it.isNullOrEmpty()) {
+                binding.rvFollow.gone()
+                binding.vErrorView.show(
+                    errorEmptyResId = APP_R.drawable.common_list_empty_ic,
+                    title = APP_R.string.commonui_list_empty
+                )
+            } else {
+                binding.rvFollow.show()
+                binding.vErrorView.gone()
+            }
+        }
+        viewModel.followListRltLD.observe(viewLifecycleOwner) { rlt ->
+            binding.vRefresh.finishRefresh()
+            binding.vRefresh.finishLoadMore()
+            showFailedToast(rlt)
+        }
+    }
+
+    override fun follow(item: FollowItemData, position: Int) {
+        if (item.data.uid.isEmpty()) {
+            return
+        }
+        viewModel.follow(item.data.uid).observe(viewLifecycleOwner) { rlt ->
+            when (rlt) {
+                is Rlt.Success -> {
+                    listAdapter.notifyItemChanged(position)
+                }
+
+                is Rlt.Failed -> {
+                    showFailedToast(rlt)
+                }
+            }
+        }
+    }
+
+    override fun unFollow(item: FollowItemData, position: Int) {
+        if (item.data.uid.isEmpty()) {
+            return
+        }
+        viewModel.unFollow(item.data.uid).observe(viewLifecycleOwner) { rlt ->
+            when (rlt) {
+                is Rlt.Success -> {
+                    listAdapter.notifyItemChanged(position)
+                }
+
+                is Rlt.Failed -> {
+                    showFailedToast(rlt)
+                }
+            }
+        }
+    }
+
+    override fun goProfile(uid: String) {
+        val act = activity ?: return
+        Router.build(act, Profile.UserProfile.PATH)
+            .putExtra(Profile.Common.EXTRA_UID, uid)
+            .start()
+    }
+
+}

+ 79 - 6
module/profile/src/main/java/com/adealink/weparty/profile/relation/RelationShipActivity.kt

@@ -1,24 +1,33 @@
 package com.adealink.weparty.profile.relation
 
 import android.os.Bundle
+import android.util.TypedValue
 import androidx.activity.viewModels
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.updateLayoutParams
 import androidx.fragment.app.Fragment
+import com.adealink.frame.aab.util.getCompatColor
+import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.mvvm.view.viewBinding
 import com.adealink.frame.router.Router
 import com.adealink.frame.router.annotation.BindExtra
 import com.adealink.frame.router.annotation.RouterUri
 import com.adealink.frame.util.statusBarHeight
 import com.adealink.weparty.commonui.BaseActivity
+import com.adealink.weparty.commonui.ext.gone
+import com.adealink.weparty.commonui.ext.show
 import com.adealink.weparty.commonui.recycleview.adapter.BaseActivityTabFragmentStateAdapter
 import com.adealink.weparty.commonui.widget.EmptyFragment
+import com.adealink.weparty.databinding.LayoutHomeTabBinding
 import com.adealink.weparty.module.profile.Profile
+import com.adealink.weparty.profile.R
 import com.adealink.weparty.profile.databinding.ActivityProfileRelationshipBinding
 import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
 import com.adealink.weparty.profile.relation.viewmodel.RELATIONSHIP_TABS
 import com.adealink.weparty.profile.relation.viewmodel.RelationShipTab
 import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
+import com.google.android.material.tabs.TabLayout
+import com.google.android.material.tabs.TabLayoutMediator
 
 @RouterUri(
     path = [Profile.RelationShip.PATH],
@@ -33,6 +42,9 @@ class RelationShipActivity : BaseActivity() {
     private val viewModel by viewModels<FollowViewModel> { ProfileViewModelFactory() }
     private lateinit var pageAdapter: PageAdapter
 
+    private var followCount: Int? = null
+    private var fansCount: Int? = null
+
     override fun onBeforeCreate() {
         super.onBeforeCreate()
         Router.bind(this)
@@ -46,24 +58,85 @@ class RelationShipActivity : BaseActivity() {
         }
 
         pageAdapter = PageAdapter()
+        binding.vpContent.offscreenPageLimit = 1
         binding.vpContent.adapter = pageAdapter
-        binding.vTab.createMediatorAndAttach(
+        binding.vpContent.isSaveEnabled = false
+        TabLayoutMediator(
+            binding.tlTab,
             binding.vpContent,
-            pageAdapter,
-            tabIndex.coerceIn(0, RELATIONSHIP_TABS.size - 1)
-        )
+            true,
+            false
+        ) { tabLayout, position ->
+            tabLayout.setCustomView(com.adealink.weparty.R.layout.layout_home_tab)
+            tabLayout.customView?.let { tabView ->
+                val tabViewBinding = LayoutHomeTabBinding.bind(tabView)
+                onConfigureTab(tabViewBinding, position)
+                updateTabView(
+                    tabLayout,
+                    0 == position
+                )
+            }
+        }.attach()
+        binding.tlTab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+
+            override fun onTabSelected(tab: TabLayout.Tab?) {
+                updateTabView(tab, true)
+            }
+
+            override fun onTabUnselected(tab: TabLayout.Tab?) {
+                updateTabView(tab, false)
+            }
 
+            override fun onTabReselected(tab: TabLayout.Tab?) {
+            }
+
+        })
+        binding.vpContent.currentItem = tabIndex
+    }
+
+    private fun onConfigureTab(binding: LayoutHomeTabBinding, position: Int) {
+        binding.tvTab.text = pageAdapter.getTabName(position)
+    }
+
+    private fun updateTabView(
+        tabView: TabLayout.Tab?,
+        isSelected: Boolean
+    ) {
+        tabView?.customView?.let { tabView ->
+            val tabViewBinding = LayoutHomeTabBinding.bind(tabView)
+            if (isSelected) {
+                tabViewBinding.ivTabBg.show()
+                tabViewBinding.tvTab.setTextColor(getCompatColor(com.adealink.weparty.R.color.color_FF1D2129))
+                tabViewBinding.tvTab.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22f)
+            } else {
+                tabViewBinding.ivTabBg.gone()
+                tabViewBinding.tvTab.setTextColor(getCompatColor(com.adealink.weparty.R.color.color_FF4E5969))
+                tabViewBinding.tvTab.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
+            }
+        }
     }
 
     override fun observeViewModel() {
         super.observeViewModel()
-        viewModel
+
     }
 
     internal inner class PageAdapter : BaseActivityTabFragmentStateAdapter(this) {
 
         override fun getTabName(pos: Int): String {
-            return ""
+            val tab = RELATIONSHIP_TABS.getOrNull(pos) ?: return ""
+            return when (tab.type) {
+                RelationShipTab.FANS -> {
+                    getCompatString(
+                        R.string.profile_follow_list_title,
+                        followCount?.toString() ?: ""
+                    )
+                }
+
+                RelationShipTab.FOLLOW -> {
+                    getCompatString(R.string.profile_fans_list_title, fansCount?.toString() ?: "")
+                }
+            }
         }
 
         override fun getItemCount(): Int {

+ 30 - 8
module/profile/src/main/java/com/adealink/weparty/profile/relation/adapter/FansItemViewBinder.kt

@@ -5,22 +5,44 @@ import android.view.ViewGroup
 import com.adealink.frame.util.onClick
 import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
 import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
+import com.adealink.weparty.module.profile.data.FollowStatus
+import com.adealink.weparty.profile.R
 import com.adealink.weparty.profile.databinding.ItemRelationshipFansBinding
-import com.adealink.weparty.profile.relation.data.FollowItemData
+import com.adealink.weparty.profile.relation.data.FansItemData
 
 
 class FansItemViewBinder(val listener: OnFansItemClick) :
-    ItemViewBinder<FollowItemData, BindingViewHolder<ItemRelationshipFansBinding>>() {
+    ItemViewBinder<FansItemData, BindingViewHolder<ItemRelationshipFansBinding>>() {
 
     override fun onBindViewHolder(
         holder: BindingViewHolder<ItemRelationshipFansBinding>,
-        item: FollowItemData,
+        item: FansItemData,
     ) {
         holder.binding.root.onClick {
-            listener.goProfile(item.user.uid)
+            listener.goProfile(item.data.uid)
+        }
+        holder.binding.ivAvatar.setImageUrl(item.data.avatar)
+        holder.binding.tvUserName.text = item.data.nickName
+        holder.binding.vGender.setGender(item.data.gender)
+        holder.binding.vGender.setAge(item.data.age)
+
+        when (FollowStatus.map(item.data.followStatus)) {
+            FollowStatus.NONE,
+            FollowStatus.FANS -> {
+                holder.binding.btnEachFollow.setImageResource(R.drawable.profile_each_follow_button_ic)
+                holder.binding.btnEachFollow.onClick {
+                    listener.follow(item, holder.layoutPosition)
+                }
+            }
+
+            FollowStatus.FOLLOW,
+            FollowStatus.EACH_FOLLOW -> {
+                holder.binding.btnEachFollow.setImageResource(R.drawable.profile_each_unfollow_button_ic)
+                holder.binding.btnEachFollow.onClick {
+                    listener.unFollow(item, holder.layoutPosition)
+                }
+            }
         }
-        holder.binding.ivAvatar.setImageUrl(item.user.avatar)
-        holder.binding.tvUserName.text = item.user.nickName
     }
 
     override fun onCreateViewHolder(
@@ -37,8 +59,8 @@ class FansItemViewBinder(val listener: OnFansItemClick) :
     }
 
     interface OnFansItemClick {
-        fun eachFollow(uid: String)
-        fun unEachFollow(uid: String)
+        fun follow(item: FansItemData, position: Int)
+        fun unFollow(item: FansItemData, position: Int)
 
         fun goProfile(uid: String)
     }

+ 48 - 6
module/profile/src/main/java/com/adealink/weparty/profile/relation/adapter/FollowItemViewBinder.kt

@@ -2,12 +2,18 @@ package com.adealink.weparty.profile.relation.adapter
 
 import android.view.LayoutInflater
 import android.view.ViewGroup
+import com.adealink.frame.aab.util.getCompatColor
+import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.util.onClick
+import com.adealink.weparty.commonui.ext.gone
+import com.adealink.weparty.commonui.ext.show
 import com.adealink.weparty.commonui.recycleview.adapter.BindingViewHolder
 import com.adealink.weparty.commonui.recycleview.adapter.multitype.ItemViewBinder
+import com.adealink.weparty.module.profile.data.FollowStatus
+import com.adealink.weparty.profile.R
 import com.adealink.weparty.profile.databinding.ItemRelationshipFollowBinding
 import com.adealink.weparty.profile.relation.data.FollowItemData
-
+import com.adealink.weparty.R as APP_R
 
 class FollowItemViewBinder(val listener: OnFollowItemClick) :
     ItemViewBinder<FollowItemData, BindingViewHolder<ItemRelationshipFollowBinding>>() {
@@ -17,10 +23,46 @@ class FollowItemViewBinder(val listener: OnFollowItemClick) :
         item: FollowItemData,
     ) {
         holder.binding.root.onClick {
-            listener.goProfile(item.user.uid)
+            listener.goProfile(item.data.uid)
+        }
+        holder.binding.ivAvatar.setImageUrl(item.data.avatar)
+        holder.binding.tvUserName.text = item.data.nickName
+        holder.binding.vGender.setGender(item.data.gender)
+        holder.binding.vGender.setAge(item.data.age)
+
+        when (FollowStatus.map(item.data.followStatus)) {
+            FollowStatus.NONE,
+            FollowStatus.FANS -> {
+                holder.binding.btnFollow.show()
+                holder.binding.btnFollow.setBackgroundResource(R.drawable.profile_follow_button_bg)
+                holder.binding.btnFollow.text = getCompatString(APP_R.string.common_follow)
+                holder.binding.btnFollow.setTextColor(getCompatColor(APP_R.color.white))
+                holder.binding.btnFollow.onClick {
+                    listener.follow(item, holder.layoutPosition)
+                }
+                holder.binding.btnEachFollow.gone()
+            }
+
+            FollowStatus.EACH_FOLLOW -> {
+                holder.binding.btnFollow.gone()
+                holder.binding.btnEachFollow.show()
+                holder.binding.btnEachFollow.onClick {
+                    listener.unFollow(item, holder.layoutPosition)
+                }
+            }
+
+            FollowStatus.FOLLOW -> {
+                holder.binding.btnFollow.show()
+                holder.binding.btnFollow.setBackgroundResource(R.drawable.profile_followed_button_bg)
+                holder.binding.btnFollow.text = getCompatString(APP_R.string.common_unfollow)
+                holder.binding.btnFollow.setTextColor(getCompatColor(APP_R.color.color_FFC9CDD4))
+                holder.binding.btnFollow.onClick {
+                    listener.unFollow(item, holder.layoutPosition)
+                }
+                holder.binding.btnEachFollow.gone()
+
+            }
         }
-        holder.binding.ivAvatar.setImageUrl(item.user.avatar)
-        holder.binding.tvUserName.text = item.user.nickName
     }
 
     override fun onCreateViewHolder(
@@ -37,8 +79,8 @@ class FollowItemViewBinder(val listener: OnFollowItemClick) :
     }
 
     interface OnFollowItemClick {
-        fun follow(uid: String)
-        fun unFollow(uid: String)
+        fun follow(item: FollowItemData, position: Int)
+        fun unFollow(item: FollowItemData, position: Int)
 
         fun goProfile(uid: String)
     }

+ 36 - 11
module/profile/src/main/java/com/adealink/weparty/profile/relation/data/RelationShipData.kt

@@ -1,8 +1,7 @@
 package com.adealink.weparty.profile.relation.data
 
-import com.adealink.frame.network.data.PageReq
 import com.adealink.weparty.commonui.recycleview.diffutil.BaseListItemData
-import com.adealink.weparty.module.profile.data.UserInfo
+import com.google.gson.annotations.GsonNullable
 import com.google.gson.annotations.SerializedName
 
 
@@ -27,28 +26,54 @@ data class FollowStatusData(
 
 
 data class FollowListReq(
-    @SerializedName("page") val page: PageReq
+    @SerializedName("size") val size: Int,
+    @SerializedName("next") val next: String?
 )
 
 data class FollowListRes(
-    @SerializedName("list") val list: List<FollowData>
+    @SerializedName("list") val list: List<FollowData>,
+    @GsonNullable
+    @SerializedName("next") val next: String?
 )
 
 data class FollowData(
-    @SerializedName("user") val user: UserInfo
+    @SerializedName("userNo") val uid: String,
+    @GsonNullable
+    @SerializedName("nickname") var nickName: String? = null,
+    @GsonNullable
+    @SerializedName("avatar") var avatar: String? = null,
+    @GsonNullable
+    @SerializedName("gender") var gender: Int? = null,
+    @GsonNullable
+    @SerializedName("age") var age: Int? = null,
+    @GsonNullable
+    @SerializedName("relateion") var followStatus: Int? = null
 )
 
 
 data class FansListReq(
-    @SerializedName("page") val page: PageReq
+    @SerializedName("size") val size: Int,
+    @SerializedName("next") val next: String?
 )
 
-data class FansLlistRes(
-    @SerializedName("list") val list: List<FansData>
+data class FansListRes(
+    @SerializedName("list") val list: List<FansData>,
+    @GsonNullable
+    @SerializedName("next") val next: String?
 )
 
 data class FansData(
-    @SerializedName("user") val user: UserInfo
+    @SerializedName("userNo") val uid: String,
+    @GsonNullable
+    @SerializedName("nickname") var nickName: String? = null,
+    @GsonNullable
+    @SerializedName("avatar") var avatar: String? = null,
+    @GsonNullable
+    @SerializedName("gender") var gender: Int? = null,
+    @GsonNullable
+    @SerializedName("age") var age: Int? = null,
+    @GsonNullable
+    @SerializedName("relateion") var followStatus: Int? = null
 )
 
 
@@ -56,10 +81,10 @@ sealed class BaseRelationShipItemData : BaseListItemData
 
 
 data class FollowItemData(
-    val user: UserInfo
+    val data: FollowData
 ) : BaseRelationShipItemData()
 
 
 data class FansItemData(
-    val user: UserInfo
+    val data: FansData
 ) : BaseRelationShipItemData()

+ 66 - 16
module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/FollowViewModel.kt

@@ -11,14 +11,13 @@ import com.adealink.weparty.module.profile.data.FollowStatus
 import com.adealink.weparty.module.profile.viewmodel.IFollowViewModel
 import com.adealink.weparty.profile.datasource.remote.FollowHttpService
 import com.adealink.weparty.profile.relation.data.FansItemData
-import com.adealink.weparty.profile.relation.data.FollowData
+import com.adealink.weparty.profile.relation.data.FansListReq
 import com.adealink.weparty.profile.relation.data.FollowItemData
+import com.adealink.weparty.profile.relation.data.FollowListReq
 import com.adealink.weparty.profile.relation.data.FollowReq
-import com.adealink.weparty.profile.relation.data.FollowStatusData
 import com.adealink.weparty.profile.relation.data.FollowStatusReq
 import com.adealink.weparty.util.PageHandler
 import kotlinx.coroutines.launch
-import kotlin.String
 
 class FollowViewModel : BaseViewModel(), IFollowViewModel {
 
@@ -119,9 +118,9 @@ class FollowViewModel : BaseViewModel(), IFollowViewModel {
                 }
             }
 
-            FollowStatus.MUTUAL_FOLLOW -> {
+            FollowStatus.EACH_FOLLOW -> {
                 if (follow) {
-                    FollowStatus.MUTUAL_FOLLOW
+                    FollowStatus.EACH_FOLLOW
                 } else {
                     FollowStatus.FANS
                 }
@@ -129,7 +128,7 @@ class FollowViewModel : BaseViewModel(), IFollowViewModel {
 
             FollowStatus.FANS -> {
                 if (follow) {
-                    FollowStatus.MUTUAL_FOLLOW
+                    FollowStatus.EACH_FOLLOW
                 } else {
                     FollowStatus.FANS
                 }
@@ -149,33 +148,84 @@ class FollowViewModel : BaseViewModel(), IFollowViewModel {
 
 
     private val followList = mutableListOf<FollowItemData>()
+    private val followUids = mutableSetOf<String>()
     private val followPageHandler = PageHandler()
-    val followListLD = MutableLiveData<List<FollowItemData>>()
-    fun pullFollowed() {
-        viewModelScope.launch {
 
-        }
+    val followListRltLD = ExtMutableLiveData<Rlt<Any>>()
+    val followListLD = MutableLiveData<List<FollowItemData>>()
+    fun pullFollowList() {
+        followList.clear()
+        followUids.clear()
+        followPageHandler.reset()
+        loadMoreFollowList()
     }
 
-    fun loadMoreFollowed() {
+    fun loadMoreFollowList() {
         viewModelScope.launch {
+            val rlt = followHttpService.pullFollow(
+                FollowListReq(
+                    size = followPageHandler.pageSize,
+                    next = followPageHandler.currentPage
+                )
+            )
+            when (rlt) {
+                is Rlt.Failed -> {
+                    followListRltLD.send(rlt)
+                }
 
+                is Rlt.Success -> {
+                    followPageHandler.nextPage(rlt.data.data?.next)
+                    rlt.data.data?.list?.forEach {
+                        if (!followUids.contains(it.uid)) {
+                            followList.add(FollowItemData(it))
+                            followUids.add(it.uid)
+                        }
+                    }
+                    followListRltLD.send(rlt)
+                    followListLD.send(followList)
+                }
+            }
         }
     }
 
 
     private val fansList = mutableListOf<FansItemData>()
+    private val fansUids = mutableSetOf<String>()
     private val fansPageHandler = PageHandler()
+    val fansListRltLD = ExtMutableLiveData<Rlt<Any>>()
     val fansListLD = MutableLiveData<List<FansItemData>>()
-    fun pullFans() {
-        viewModelScope.launch {
-
-        }
+    fun pullFansList() {
+        fansList.clear()
+        fansUids.clear()
+        fansPageHandler.reset()
+        loadMoreFansList()
     }
 
-    fun loadMoreFans() {
+    fun loadMoreFansList() {
         viewModelScope.launch {
+            val rlt = followHttpService.pullFans(
+                FansListReq(
+                    size = fansPageHandler.pageSize,
+                    next = fansPageHandler.currentPage
+                )
+            )
+            when (rlt) {
+                is Rlt.Failed -> {
+                    fansListRltLD.send(rlt)
+                }
 
+                is Rlt.Success -> {
+                    fansPageHandler.nextPage(rlt.data.data?.next)
+                    rlt.data.data?.list?.forEach {
+                        if (!fansUids.contains(it.uid)) {
+                            fansList.add(FansItemData(it))
+                            fansUids.add(it.uid)
+                        }
+                    }
+                    fansListRltLD.send(rlt)
+                    fansListLD.send(fansList)
+                }
+            }
         }
     }
 }

+ 2 - 2
module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/RelationShipTab.kt

@@ -1,8 +1,8 @@
 package com.adealink.weparty.profile.relation.viewmodel
 
 import com.adealink.weparty.commonui.BaseFragment
-import com.adealink.weparty.profile.relation.viewmodel.fans.FansFragment
-import com.adealink.weparty.profile.relation.viewmodel.follow.FollowFragment
+import com.adealink.weparty.profile.relation.FansFragment
+import com.adealink.weparty.profile.relation.FollowFragment
 
 enum class RelationShipTab(val index: Int) {
     /**

+ 0 - 71
module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/fans/FansFragment.kt

@@ -1,71 +0,0 @@
-package com.adealink.weparty.profile.relation.viewmodel.fans
-
-import androidx.fragment.app.activityViewModels
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.adealink.frame.base.fastLazy
-import com.adealink.frame.mvvm.view.viewBinding
-import com.adealink.frame.router.Router
-import com.adealink.weparty.commonui.BaseFragment
-import com.adealink.weparty.commonui.ext.dp
-import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
-import com.adealink.weparty.commonui.recycleview.itemdecoration.VerticalSpaceItemDecoration
-import com.adealink.weparty.module.profile.Profile
-import com.adealink.weparty.module.profile.ProfileModule
-import com.adealink.weparty.module.profile.data.UserInfo
-import com.adealink.weparty.profile.R
-import com.adealink.weparty.profile.databinding.FragmentFansBinding
-import com.adealink.weparty.profile.relation.adapter.FansItemViewBinder
-import com.adealink.weparty.profile.relation.data.BaseRelationShipItemData
-import com.adealink.weparty.profile.relation.data.FansItemData
-import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
-import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
-
-class FansFragment : BaseFragment(R.layout.fragment_fans), FansItemViewBinder.OnFansItemClick {
-    private val binding by viewBinding(FragmentFansBinding::bind)
-    private val viewModel by activityViewModels<FollowViewModel> { ProfileViewModelFactory() }
-    private val listAdapter by fastLazy { MultiTypeListAdapter<BaseRelationShipItemData>() }
-    override fun initViews() {
-        super.initViews()
-        listAdapter.register(FansItemViewBinder(this))
-        binding.rvFans.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
-        binding.rvFans.adapter = listAdapter
-        binding.rvFans.addItemDecoration(
-            VerticalSpaceItemDecoration(20.dp())
-        )
-    }
-
-    override fun loadData() {
-        super.loadData()
-        listAdapter.submitList(
-            listOf(
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FansItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-            )
-        )
-    }
-
-    override fun observeViewModel() {
-        super.observeViewModel()
-    }
-
-    override fun eachFollow(uid: String) {
-    }
-
-    override fun unEachFollow(uid: String) {
-    }
-
-    override fun goProfile(uid: String) {
-        val act = activity ?: return
-        Router.build(act, Profile.UserProfile.PATH)
-            .putExtra(Profile.Common.EXTRA_UID, uid)
-            .start()
-    }
-
-}

+ 0 - 75
module/profile/src/main/java/com/adealink/weparty/profile/relation/viewmodel/follow/FollowFragment.kt

@@ -1,75 +0,0 @@
-package com.adealink.weparty.profile.relation.viewmodel.follow
-
-import androidx.fragment.app.activityViewModels
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.adealink.frame.base.fastLazy
-import com.adealink.frame.mvvm.view.viewBinding
-import com.adealink.frame.router.Router
-import com.adealink.weparty.commonui.BaseFragment
-import com.adealink.weparty.commonui.ext.dp
-import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
-import com.adealink.weparty.commonui.recycleview.itemdecoration.VerticalSpaceItemDecoration
-import com.adealink.weparty.module.profile.Profile
-import com.adealink.weparty.module.profile.ProfileModule
-import com.adealink.weparty.module.profile.data.UserInfo
-import com.adealink.weparty.profile.R
-import com.adealink.weparty.profile.databinding.FragmentFollowBinding
-import com.adealink.weparty.profile.relation.adapter.FollowItemViewBinder
-import com.adealink.weparty.profile.relation.data.BaseRelationShipItemData
-import com.adealink.weparty.profile.relation.data.FollowItemData
-import com.adealink.weparty.profile.relation.viewmodel.FollowViewModel
-import com.adealink.weparty.profile.viewmodel.ProfileViewModelFactory
-
-class FollowFragment : BaseFragment(R.layout.fragment_follow),
-    FollowItemViewBinder.OnFollowItemClick {
-
-    private val binding by viewBinding(FragmentFollowBinding::bind)
-    private val viewModel by activityViewModels<FollowViewModel> { ProfileViewModelFactory() }
-    private val listAdapter by fastLazy { MultiTypeListAdapter<BaseRelationShipItemData>() }
-
-    override fun initViews() {
-        super.initViews()
-        listAdapter.register(FollowItemViewBinder(this))
-        binding.rvFollow.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
-        binding.rvFollow.adapter = listAdapter
-        binding.rvFollow.addItemDecoration(
-            VerticalSpaceItemDecoration(20.dp())
-        )
-    }
-
-    override fun loadData() {
-        super.loadData()
-        // TODO: 测试
-        listAdapter.submitList(
-            listOf(
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-                FollowItemData(ProfileModule.getMyUserInfo() ?: UserInfo.emptyUserInfo("123", "")),
-            )
-        )
-    }
-
-    override fun observeViewModel() {
-        super.observeViewModel()
-    }
-
-    override fun follow(uid: String) {
-    }
-
-    override fun unFollow(uid: String) {
-    }
-
-    override fun goProfile(uid: String) {
-        val act = activity ?: return
-        Router.build(act, Profile.UserProfile.PATH)
-            .putExtra(Profile.Common.EXTRA_UID, uid)
-            .start()
-    }
-
-}

+ 1 - 1
module/profile/src/main/java/com/adealink/weparty/profile/search/adapter/SearchItemViewBinder.kt

@@ -33,7 +33,7 @@ class SearchItemViewBinder(val listener: OnResultClickListener) :
                 (item.data.followCount ?: 0).toString()
             )
         if (item.data.follow == true) {
-            holder.binding.btnFollow.setBackgroundResource(R.drawable.profile_followed_btn_bg)
+            holder.binding.btnFollow.setBackgroundResource(R.drawable.profile_followed_button_bg)
             holder.binding.btnFollow.onClick {
                 listener.unFollow(item.data.uid)
             }

+ 0 - 0
module/profile/src/main/res/drawable/profile_followed_btn_bg.xml → module/profile/src/main/res/drawable/profile_followed_button_bg.xml


+ 13 - 5
module/profile/src/main/res/layout/activity_profile_relationship.xml

@@ -20,14 +20,22 @@
             app:layout_constraintTop_toTopOf="parent"
             app:srcCompat="@drawable/commonui_back_black_48_ic" />
 
-        <com.adealink.weparty.commonui.widget.CommonTabLayout
-            android:id="@+id/v_tab"
+        <com.google.android.material.tabs.TabLayout
+            android:id="@+id/tl_tab"
             android:layout_width="0dp"
-            android:layout_height="0dp"
-            app:layout_constraintBottom_toBottomOf="parent"
+            android:layout_height="match_parent"
+            app:layout_constrainedWidth="true"
             app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0"
             app:layout_constraintStart_toEndOf="@id/iv_back"
-            app:layout_constraintTop_toTopOf="parent" />
+            app:layout_constraintTop_toTopOf="parent"
+            app:tabBackground="@null"
+            app:tabGravity="start"
+            app:tabIndicatorHeight="0dp"
+            app:tabMinWidth="0dp"
+            app:tabMode="fixed"
+            app:tabPadding="0dp"
+            app:tabRippleColor="@null" />
     </androidx.constraintlayout.widget.ConstraintLayout>
 
     <androidx.viewpager2.widget.ViewPager2

+ 13 - 1
module/profile/src/main/res/layout/fragment_fans.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
@@ -11,7 +12,18 @@
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/rv_fans"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            android:paddingHorizontal="16dp" />
     </com.scwang.smart.refresh.layout.SmartRefreshLayout>
 
+    <com.adealink.weparty.commonui.widget.CommonEmptyErrorView
+        android:id="@+id/v_error_view"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 13 - 1
module/profile/src/main/res/layout/fragment_follow.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
@@ -11,7 +12,18 @@
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/rv_follow"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            android:paddingHorizontal="16dp" />
     </com.scwang.smart.refresh.layout.SmartRefreshLayout>
 
+    <com.adealink.weparty.commonui.widget.CommonEmptyErrorView
+        android:id="@+id/v_error_view"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 3 - 22
module/profile/src/main/res/layout/item_relationship_fans.xml

@@ -27,6 +27,8 @@
         app:layout_constrainedWidth="true"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toStartOf="@id/v_gender"
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constraintHorizontal_chainStyle="packed"
         app:layout_constraintStart_toEndOf="@id/iv_avatar"
         app:layout_constraintTop_toTopOf="parent"
         tools:text="Super Beautiful Girl" />
@@ -40,33 +42,12 @@
         app:layout_constraintStart_toEndOf="@id/tv_user_name"
         app:layout_constraintTop_toTopOf="@id/tv_user_name" />
 
-
     <androidx.constraintlayout.widget.Barrier
         android:id="@+id/right_barrier"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         app:barrierDirection="start"
-        app:constraint_referenced_ids="btn_follow,
-        " />
-
-    <androidx.appcompat.widget.AppCompatTextView
-        android:id="@+id/btn_follow"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="12dp"
-        android:includeFontPadding="false"
-        android:minWidth="36dp"
-        android:paddingHorizontal="8dp"
-        android:paddingVertical="4dp"
-        android:singleLine="true"
-        android:textSize="14sp"
-        app:layout_constrainedWidth="true"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/btn_each_follow"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:background="@drawable/profile_follow_button_bg"
-        tools:text="follow"
-        tools:textColor="@color/white" />
+        app:constraint_referenced_ids="btn_each_follow" />
 
     <androidx.appcompat.widget.AppCompatImageView
         android:id="@+id/btn_each_follow"

+ 5 - 4
module/profile/src/main/res/layout/item_relationship_follow.xml

@@ -27,9 +27,11 @@
         app:layout_constrainedWidth="true"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toStartOf="@id/v_gender"
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constraintHorizontal_chainStyle="packed"
         app:layout_constraintStart_toEndOf="@id/iv_avatar"
         app:layout_constraintTop_toTopOf="parent"
-        tools:text="Super Beautiful Girl" />
+        tools:text="Super Beautiful GirlSuper Beautiful GirlSuper Beautiful GirlSuper Beautiful Girl" />
 
     <com.adealink.weparty.module.profile.widget.GenderView
         android:id="@+id/v_gender"
@@ -40,14 +42,12 @@
         app:layout_constraintStart_toEndOf="@id/tv_user_name"
         app:layout_constraintTop_toTopOf="@id/tv_user_name" />
 
-
     <androidx.constraintlayout.widget.Barrier
         android:id="@+id/right_barrier"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         app:barrierDirection="start"
-        app:constraint_referenced_ids="btn_follow,
-        " />
+        app:constraint_referenced_ids="btn_follow,btn_each_follow" />
 
     <androidx.appcompat.widget.AppCompatTextView
         android:id="@+id/btn_follow"
@@ -59,6 +59,7 @@
         android:paddingHorizontal="8dp"
         android:paddingVertical="4dp"
         android:singleLine="true"
+        android:textColor="@color/white"
         android:textSize="14sp"
         app:layout_constrainedWidth="true"
         app:layout_constraintBottom_toBottomOf="parent"

+ 2 - 0
module/profile/src/main/res/values/strings.xml

@@ -63,4 +63,6 @@
     <string name="profile_edit_talent_voice_re_record">重录</string>
     <string name="profile_edit_talent_voice_preview">试听</string>
     <string name="profile_edit_talent_voice_delete_record">删除并重新录制</string>
+    <string name="profile_follow_list_title">%s Followed</string>
+    <string name="profile_fans_list_title">%s Fans</string>
 </resources>