From b223e8ab3b6b5b82f9fabe8b261a4492a9247560 Mon Sep 17 00:00:00 2001 From: Taras Smakula <tarassmakula@gmail.com> Date: Fri, 8 Mar 2024 14:04:30 +0200 Subject: [PATCH] Add loading for follow/unfollow on user fragment --- .../core/feature/user/UserDialogFragment.kt | 2 +- .../core/feature/user/UserViewModel.kt | 43 ++++++++++++++++++- .../user/list/UsersCircleViewHolder.kt | 5 ++- .../circles/core/model/TimelineListItem.kt | 3 +- .../res/layout/list_item_users_timeline.xml | 10 +++++ 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt b/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt index 5530503eb..b35cd9e37 100644 --- a/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt +++ b/core/src/main/java/org/futo/circles/core/feature/user/UserDialogFragment.kt @@ -120,7 +120,7 @@ class UserDialogFragment : BaseFullscreenDialogFragment(DialogFragmentUserBindin } } viewModel.userLiveData.observeData(this) { setupUserInfo(it) } - viewModel.timelineLiveDataLiveData.observeData(this) { + viewModel.usersTimelinesLiveData.observeData(this) { usersCirclesAdapter.submitList(it) } viewModel.requestFollowLiveData.observeResponse(this, diff --git a/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt b/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt index 36ecdbea7..e3ba56c33 100644 --- a/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt +++ b/core/src/main/java/org/futo/circles/core/feature/user/UserViewModel.kt @@ -1,5 +1,6 @@ package org.futo.circles.core.feature.user +import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel @@ -15,7 +16,9 @@ import org.futo.circles.core.extensions.launchUi import org.futo.circles.core.feature.room.RoomRelationsBuilder import org.futo.circles.core.feature.room.invite.ManageInviteRequestsDataSource import org.futo.circles.core.feature.workspace.SharedCircleDataSource +import org.futo.circles.core.model.TimelineHeaderItem import org.futo.circles.core.model.TimelineListItem +import org.futo.circles.core.model.TimelineRoomListItem import org.futo.circles.core.provider.MatrixSessionProvider import org.matrix.android.sdk.api.session.getRoom import javax.inject.Inject @@ -34,7 +37,7 @@ class UserViewModel @Inject constructor( private val profileRoomId = sharedCircleDataSource.getSharedCirclesSpaceId() ?: "" val userLiveData = userDataSource.userLiveData - val timelineLiveDataLiveData = MutableLiveData<List<TimelineListItem>>() + val requestFollowLiveData = SingleEventLiveData<Response<Unit?>>() val inviteToConnectLiveData = SingleEventLiveData<Response<Unit?>>() val ignoreUserLiveData = SingleEventLiveData<Response<Unit?>>() @@ -44,6 +47,29 @@ class UserViewModel @Inject constructor( it.firstOrNull { it.userId == userId } != null } + private val timelineLiveData = MutableLiveData<List<TimelineListItem>>() + private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet()) + + val usersTimelinesLiveData = MediatorLiveData<List<TimelineListItem>>().also { + it.addSource(loadingItemsIdsList) { loadingItemsValue -> + val currentList = it.value ?: emptyList() + it.postValue( + currentList.map { item -> + when (item) { + is TimelineRoomListItem -> item.copy( + isLoading = loadingItemsValue.contains(item.id) + ) + + is TimelineHeaderItem -> item + } + } + ) + } + it.addSource(timelineLiveData) { value -> + it.postValue(value) + } + } + init { getUsersTimelines() } @@ -51,16 +77,18 @@ class UserViewModel @Inject constructor( private fun getUsersTimelines() { launchUi { userDataSource.getTimelinesFlow().collectLatest { - timelineLiveDataLiveData.postValue(it) + timelineLiveData.postValue(it) } } } fun requestFollowTimeline(timelineId: String) { launchBg { + toggleItemLoading(timelineId) val result = createResult { MatrixSessionProvider.currentSession?.roomService()?.knock(timelineId) } + toggleItemLoading(timelineId) requestFollowLiveData.postValue(result) } } @@ -68,8 +96,10 @@ class UserViewModel @Inject constructor( fun unFollowTimeline(timelineId: String) { launchBg { createResult { + toggleItemLoading(timelineId) roomRelationsBuilder.removeFromAllParents(timelineId) MatrixSessionProvider.currentSession?.roomService()?.leaveRoom(timelineId) + toggleItemLoading(timelineId) } } } @@ -109,4 +139,13 @@ class UserViewModel @Inject constructor( } } + private fun toggleItemLoading(id: String) { + val currentSet = loadingItemsIdsList.value?.toMutableSet() ?: return + val newLoadingSet = currentSet.apply { + if (this.contains(id)) remove(id) + else add(id) + } + loadingItemsIdsList.postValue(newLoadingSet) + } + } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt b/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt index a9158a2cb..543077234 100644 --- a/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt +++ b/core/src/main/java/org/futo/circles/core/feature/user/list/UsersCircleViewHolder.kt @@ -39,8 +39,9 @@ class UsersTimelineRoomViewHolder( with(binding) { tvTimelineName.text = data.info.title ivTimelineImage.loadRoomProfileIcon(data.info.avatarUrl, data.info.title) - btnFollow.setIsVisible(!data.isJoined) - btnUnFollow.setIsVisible(data.isJoined) + vLoading.setIsVisible(data.isLoading) + btnFollow.setIsVisible(!data.isJoined && !data.isLoading) + btnUnFollow.setIsVisible(data.isJoined && !data.isLoading) } } } diff --git a/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt b/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt index 8c14a18de..54368d578 100644 --- a/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt +++ b/core/src/main/java/org/futo/circles/core/model/TimelineListItem.kt @@ -23,7 +23,8 @@ data class TimelineHeaderItem( data class TimelineRoomListItem( override val id: String, val info: RoomInfo, - val isJoined: Boolean + val isJoined: Boolean, + val isLoading: Boolean = false ) : TimelineListItem() fun RoomSummary.toTimelineRoomListItem() = TimelineRoomListItem( diff --git a/core/src/main/res/layout/list_item_users_timeline.xml b/core/src/main/res/layout/list_item_users_timeline.xml index 89466acb7..13107bf01 100644 --- a/core/src/main/res/layout/list_item_users_timeline.xml +++ b/core/src/main/res/layout/list_item_users_timeline.xml @@ -62,4 +62,14 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> + <ProgressBar + android:id="@+id/vLoading" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file -- GitLab