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 5db10bfeaf9619607f8fc879be465419bbccd4da..198f9f5d71f89890260ce0865cdf967f7b745b51 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 c7c3fd101834ce0b3bca279f3a310725bb0cd759..251e4f36544ae44238baca1fdef92370d1457246 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 870a1356ae05844104906c4acc542dbd80edbedb..aa75fdf4e5f86d68069de2b867f0343714c9980d 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 0000000000000000000000000000000000000000..076d5bde431857c2309e17224318b5bac171eba0 --- /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 0000000000000000000000000000000000000000..e615e42e37f2df88bcfcabe6d66c4f20b153dfc1 --- /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 2345238bb62d799150ad6ec029aa8b6d9644cbba..c417910ca8042d53a2ac43fa5a0d4113cfd68900 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 8daddeb6c4a48c2bae02cf84e5cc7c9857a10b6a..a4de40bd93e1191aa146425f012c4db6d1f5760a 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>