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 5530503eb6bd8c9f4bd859985de5f9981cb8ba42..b35cd9e37fcdf3f79494dfe7b5f4955457cd93bf 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 36ecdbea7bbeea38eb1eecd1c34e1f7bfd8c142c..e3ba56c33f0e85e86032d617521f26de5d0f3f56 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 a9158a2cb0260d351dd8f438e7947768c8b0fb1e..543077234d857f84103f421021047c3dfd41320b 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 8c14a18deab25b56bea9d285a3bba4bfd458376f..54368d5782e641fd077e984d3cf0c1cc7ad284c7 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 89466acb71cfbb2848ea025fb5e6f469d4965567..13107bf01eaaf0673875e28d5119c2de409526db 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