From b7bccfa7d5a3091da42be98258282b9b24e12ed6 Mon Sep 17 00:00:00 2001
From: Taras <tarassmakula@gmail.com>
Date: Tue, 14 Jun 2022 16:44:43 +0300
Subject: [PATCH] Add users circles list

---
 .../feature/people/user/UserDataSource.kt     | 29 +++++++++++-
 .../feature/people/user/UserFragment.kt       | 25 +++++++++-
 .../feature/people/user/UserViewModel.kt      |  1 +
 .../people/user/list/UsersCircleViewHolder.kt | 25 ++++++++++
 .../people/user/list/UsersCirclesAdapter.kt   | 20 ++++++++
 app/src/main/res/layout/user_fragment.xml     | 46 +++++++++++++++++--
 app/src/main/res/values/strings.xml           |  3 +-
 7 files changed, 142 insertions(+), 7 deletions(-)
 create mode 100644 app/src/main/java/com/futo/circles/feature/people/user/list/UsersCircleViewHolder.kt
 create mode 100644 app/src/main/java/com/futo/circles/feature/people/user/list/UsersCirclesAdapter.kt

diff --git a/app/src/main/java/com/futo/circles/feature/people/user/UserDataSource.kt b/app/src/main/java/com/futo/circles/feature/people/user/UserDataSource.kt
index 5db10bfea..198f9f5d7 100644
--- a/app/src/main/java/com/futo/circles/feature/people/user/UserDataSource.kt
+++ b/app/src/main/java/com/futo/circles/feature/people/user/UserDataSource.kt
@@ -1,12 +1,21 @@
 package com.futo.circles.feature.people.user
 
 import android.content.Context
+import androidx.lifecycle.map
 import com.futo.circles.R
+import com.futo.circles.extensions.getRoomOwners
+import com.futo.circles.mapping.toJoinedCircleListItem
+import com.futo.circles.model.CIRCLE_TAG
+import com.futo.circles.model.JoinedCircleListItem
+import com.futo.circles.model.TIMELINE_TYPE
 import com.futo.circles.provider.MatrixSessionProvider
+import org.matrix.android.sdk.api.session.room.model.Membership
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
+import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
 
 class UserDataSource(
     context: Context,
-    userId: String
+    private val userId: String
 ) {
 
     private val session by lazy {
@@ -16,4 +25,22 @@ class UserDataSource(
     }
 
     val userLiveData = session.userService().getUserLive(userId)
+
+    val userCirclesLiveData =
+        MatrixSessionProvider.currentSession?.roomService()
+            ?.getRoomSummariesLive(roomSummaryQueryParams { excludeType = null })
+            ?.map { list -> filterUsersCircles(list) }
+
+
+    private fun filterUsersCircles(list: List<RoomSummary>): List<JoinedCircleListItem> {
+        return list.mapNotNull { summary ->
+            if (isUsersCircle(summary)) summary.toJoinedCircleListItem()
+            else null
+        }.sortedBy { it.membership }
+    }
+
+    private fun isUsersCircle(summary: RoomSummary) =
+        summary.roomType == TIMELINE_TYPE && summary.membership == Membership.JOIN &&
+                getRoomOwners(summary.roomId).map { it.userId }.contains(userId)
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/circles/feature/people/user/UserFragment.kt b/app/src/main/java/com/futo/circles/feature/people/user/UserFragment.kt
index c7c3fd101..251e4f365 100644
--- a/app/src/main/java/com/futo/circles/feature/people/user/UserFragment.kt
+++ b/app/src/main/java/com/futo/circles/feature/people/user/UserFragment.kt
@@ -5,11 +5,14 @@ import android.view.View
 import androidx.appcompat.app.AppCompatActivity
 import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.navArgs
+import androidx.recyclerview.widget.DividerItemDecoration
 import by.kirich1409.viewbindingdelegate.viewBinding
 import com.futo.circles.R
 import com.futo.circles.databinding.UserFragmentBinding
 import com.futo.circles.extensions.loadProfileIcon
 import com.futo.circles.extensions.observeData
+import com.futo.circles.extensions.setIsVisible
+import com.futo.circles.feature.people.user.list.UsersCirclesAdapter
 import org.koin.androidx.viewmodel.ext.android.viewModel
 import org.koin.core.parameter.parametersOf
 import org.matrix.android.sdk.api.session.user.model.User
@@ -19,29 +22,47 @@ class UserFragment : Fragment(R.layout.user_fragment) {
 
     private val args: UserFragmentArgs by navArgs()
 
-    private val viewModel by viewModel<UserViewModel>() {
+    private val viewModel by viewModel<UserViewModel> {
         parametersOf(args.userId)
     }
     private val binding by viewBinding(UserFragmentBinding::bind)
 
+    private val usersCirclesAdapter by lazy { UsersCirclesAdapter() }
+
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
+        setupViews()
         setupObservers()
     }
 
+    private fun setupViews() {
+        binding.rvCircles.apply {
+            addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
+            adapter = usersCirclesAdapter
+        }
+    }
+
 
     private fun setupObservers() {
         viewModel.userLiveData.observeData(this) {
             it.getOrNull()?.let { user -> setupUserInfo(user) }
         }
+        viewModel.usersCirclesLiveData?.observeData(this) {
+            usersCirclesAdapter.submitList(it)
+            binding.tvEmptyCirclesList.setIsVisible(it.isEmpty())
+            binding.tvCirclesListTitle.setIsVisible(it.isNotEmpty())
+        }
     }
 
     private fun setupUserInfo(user: User) {
         with(binding) {
-            (activity as? AppCompatActivity)?.supportActionBar?.title = user.userId
+            (activity as? AppCompatActivity)?.supportActionBar?.title = user.displayName
             tvUserId.text = user.userId
             tvUserName.text = user.displayName
             ivUser.loadProfileIcon(user.avatarUrl, user.displayName ?: "")
+            tvCirclesListTitle.text = getString(R.string.users_circles_format, user.displayName)
+            tvEmptyCirclesList.text =
+                getString(R.string.not_following_any_circles_format, user.displayName)
         }
     }
 
diff --git a/app/src/main/java/com/futo/circles/feature/people/user/UserViewModel.kt b/app/src/main/java/com/futo/circles/feature/people/user/UserViewModel.kt
index 870a1356a..aa75fdf4e 100644
--- a/app/src/main/java/com/futo/circles/feature/people/user/UserViewModel.kt
+++ b/app/src/main/java/com/futo/circles/feature/people/user/UserViewModel.kt
@@ -7,4 +7,5 @@ class UserViewModel(
 ) : ViewModel() {
 
     val userLiveData = userDataSource.userLiveData
+    val usersCirclesLiveData = userDataSource.userCirclesLiveData
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/circles/feature/people/user/list/UsersCircleViewHolder.kt b/app/src/main/java/com/futo/circles/feature/people/user/list/UsersCircleViewHolder.kt
new file mode 100644
index 000000000..076d5bde4
--- /dev/null
+++ b/app/src/main/java/com/futo/circles/feature/people/user/list/UsersCircleViewHolder.kt
@@ -0,0 +1,25 @@
+package com.futo.circles.feature.people.user.list
+
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.futo.circles.core.list.ViewBindingHolder
+import com.futo.circles.databinding.AcceptCircleInviteListItemBinding
+import com.futo.circles.extensions.loadProfileIcon
+import com.futo.circles.model.JoinedCircleListItem
+
+class UsersCircleViewHolder(
+    parent: ViewGroup
+) : RecyclerView.ViewHolder(inflate(parent, AcceptCircleInviteListItemBinding::inflate)) {
+
+    private companion object : ViewBindingHolder
+
+    private val binding = baseBinding as AcceptCircleInviteListItemBinding
+
+
+    fun bind(data: JoinedCircleListItem) {
+        with(binding) {
+            tvCircleName.text = data.info.title
+            binding.ivCircleImage.loadProfileIcon(data.info.avatarUrl, data.info.title)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/circles/feature/people/user/list/UsersCirclesAdapter.kt b/app/src/main/java/com/futo/circles/feature/people/user/list/UsersCirclesAdapter.kt
new file mode 100644
index 000000000..e615e42e3
--- /dev/null
+++ b/app/src/main/java/com/futo/circles/feature/people/user/list/UsersCirclesAdapter.kt
@@ -0,0 +1,20 @@
+package com.futo.circles.feature.people.user.list
+
+import android.view.ViewGroup
+import com.futo.circles.core.list.BaseRvAdapter
+import com.futo.circles.model.JoinedCircleListItem
+
+class UsersCirclesAdapter() :
+    BaseRvAdapter<JoinedCircleListItem, UsersCircleViewHolder>(DefaultIdEntityCallback()) {
+
+    override fun onCreateViewHolder(
+        parent: ViewGroup,
+        viewType: Int
+    ): UsersCircleViewHolder = UsersCircleViewHolder(parent)
+
+
+    override fun onBindViewHolder(holder: UsersCircleViewHolder, position: Int) {
+        holder.bind(getItem(position))
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/user_fragment.xml b/app/src/main/res/layout/user_fragment.xml
index 2345238bb..c417910ca 100644
--- a/app/src/main/res/layout/user_fragment.xml
+++ b/app/src/main/res/layout/user_fragment.xml
@@ -3,14 +3,15 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:padding="4dp">
+    android:layout_height="match_parent">
 
 
     <com.google.android.material.imageview.ShapeableImageView
         android:id="@+id/ivUser"
         android:layout_width="@dimen/group_icon_size"
         android:layout_height="@dimen/group_icon_size"
+        android:layout_marginStart="4dp"
+        android:layout_marginTop="4dp"
         android:scaleType="fitCenter"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
@@ -24,6 +25,7 @@
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
         android:ellipsize="end"
         android:lines="1"
         app:layout_constraintBottom_toTopOf="@id/tvUserId"
@@ -41,7 +43,7 @@
         android:ellipsize="end"
         android:lines="1"
         app:layout_constraintBottom_toBottomOf="@id/ivUser"
-        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintEnd_toEndOf="@id/tvUserName"
         app:layout_constraintStart_toStartOf="@id/tvUserName"
         app:layout_constraintTop_toBottomOf="@id/tvUserName"
         tools:text="texsdt" />
@@ -56,5 +58,43 @@
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/ivUser" />
 
+    <TextView
+        android:id="@+id/tvCirclesListTitle"
+        style="@style/title2"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="8dp"
+        android:ellipsize="end"
+        android:gravity="center"
+        android:lines="1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/divider"
+        tools:text="user's circles" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rvCircles"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/tvCirclesListTitle" />
+
+    <TextView
+        android:id="@+id/tvEmptyCirclesList"
+        style="@style/title2"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="8dp"
+        android:gravity="center"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/divider"
+        tools:text="Not following any circles for user"
+        tools:visibility="visible" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8daddeb6c..a4de40bd9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -220,7 +220,8 @@
     <string name="choose_gallery">Choose gallery</string>
     <string name="pick_image">Pick image</string>
     <string name="unignore">Unignore</string>
-
+    <string name="not_following_any_circles_format">Not following any Circles for %s</string>
+    <string name="users_circles_format">%s\'s Circles</string>
 
     <string-array name="report_categories">
         <item>@string/crude_language</item>
-- 
GitLab