From 87dcf1840403b8dae9aed6a7e37062908dd884df Mon Sep 17 00:00:00 2001
From: Taras Smakula <tarassmakula@gmail.com>
Date: Thu, 7 Mar 2024 18:00:34 +0200
Subject: [PATCH] Add loading for knock requests

---
 .../room/knoks/KnockRequestViewModel.kt       | 33 +++++++++++++++++--
 .../room/knoks/KnockRequestsDataSource.kt     |  3 +-
 .../room/knoks/KnockRequestsDialogFragment.kt |  2 +-
 .../room/knoks/list/KnockRequestViewHolder.kt |  1 +
 .../core/model/KnockRequestListItem.kt        |  3 +-
 .../res/layout/list_item_knock_request.xml    | 22 +++++++++++++
 6 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt
index fc6c48a17..d979e513c 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestViewModel.kt
@@ -1,5 +1,7 @@
 package org.futo.circles.core.feature.room.knoks
 
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -20,18 +22,45 @@ class KnockRequestViewModel @Inject constructor(
 
     private val roomId: String = savedStateHandle.getOrThrow("roomId")
 
-    val knockRequestsLiveData = knockRequestsDataSource.getKnockRequestsListItemsLiveData(roomId)
     val inviteResultLiveData = SingleEventLiveData<Response<Unit?>>()
+    private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet())
+
+    val knockRequestsLiveData = MediatorLiveData<List<KnockRequestListItem>>().also {
+        it.addSource(loadingItemsIdsList) { loadingItemsValue ->
+            val currentList = it.value ?: emptyList()
+            it.postValue(currentList.map { item ->
+                item.copy(isLoading = loadingItemsValue.contains(item.id))
+            })
+        }
+        it.addSource(knockRequestsDataSource.getKnockRequestsListItemsLiveData(roomId)) { value ->
+            it.postValue(value)
+        }
+    }
 
     fun inviteUser(user: KnockRequestListItem) {
         launchBg {
+            toggleItemLoading(user.id)
             val result = manageInviteRequestsDataSource.inviteUser(roomId, user.requesterId)
             inviteResultLiveData.postValue(result)
+            toggleItemLoading(user.id)
         }
     }
 
     fun kickUser(user: KnockRequestListItem) {
-        launchBg { manageInviteRequestsDataSource.kickUser(roomId, user.requesterId) }
+        launchBg {
+            toggleItemLoading(user.id)
+            manageInviteRequestsDataSource.kickUser(roomId, user.requesterId)
+            toggleItemLoading(user.id)
+        }
+    }
+
+    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)
     }
 
 }
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt
index 9df217009..47767ddaa 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDataSource.kt
@@ -1,6 +1,7 @@
 package org.futo.circles.core.feature.room.knoks
 
 import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.asFlow
 import androidx.lifecycle.asLiveData
 import androidx.lifecycle.map
@@ -27,7 +28,7 @@ class KnockRequestsDataSource @Inject constructor() {
 
     fun getKnockRequestsListItemsLiveData(roomId: String) = getKnockRequestLiveData(roomId)?.map {
         it.map { user -> user.toKnockRequestListItem(roomId) }
-    }
+    } ?: MutableLiveData(emptyList())
 
     fun getKnockRequestCountLiveDataForCurrentUserInRoom(roomId: String): LiveData<Int> {
         val session = MatrixSessionProvider.getSessionOrThrow()
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt
index 03b2e2784..35eaf04c8 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/KnockRequestsDialogFragment.kt
@@ -50,7 +50,7 @@ class KnockRequestsDialogFragment :
 
     private fun setupObservers() {
         viewModel.inviteResultLiveData.observeResponse(this)
-        viewModel.knockRequestsLiveData?.observeData(this) {
+        viewModel.knockRequestsLiveData.observeData(this) {
             knocksListAdapter.submitList(it)
         }
     }
diff --git a/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt b/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt
index c0634a697..d9c6d2105 100644
--- a/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/room/knoks/list/KnockRequestViewHolder.kt
@@ -25,6 +25,7 @@ class KnockRequestViewHolder(
     }
 
     fun bind(data: KnockRequestListItem) {
+        binding.lLoading.setIsVisible(data.isLoading)
         binding.tvReason.apply {
             setIsVisible(!data.message.isNullOrBlank())
             text = data.message
diff --git a/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt b/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt
index 4b7becdc8..e3efa753e 100644
--- a/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt
+++ b/core/src/main/java/org/futo/circles/core/model/KnockRequestListItem.kt
@@ -6,7 +6,8 @@ data class KnockRequestListItem(
     val requesterId: String,
     val requesterName: String,
     val requesterAvatarUrl: String?,
-    val message: String?
+    val message: String?,
+    val isLoading: Boolean = false
 ) : IdEntity<String> {
     override val id: String = requesterId
 }
diff --git a/core/src/main/res/layout/list_item_knock_request.xml b/core/src/main/res/layout/list_item_knock_request.xml
index 60906170f..8770de68a 100644
--- a/core/src/main/res/layout/list_item_knock_request.xml
+++ b/core/src/main/res/layout/list_item_knock_request.xml
@@ -60,5 +60,27 @@ MessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessage"
         app:layout_constraintStart_toEndOf="@id/btnInvite"
         app:layout_constraintTop_toTopOf="@id/btnInvite" />
 
+    <FrameLayout
+        android:id="@+id/lLoading"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:background="?android:colorBackground"
+        android:clickable="true"
+        android:focusable="true"
+        android:outlineProvider="none"
+        android:translationZ="100dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tvReason">
+
+        <ProgressBar
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+    </FrameLayout>
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
-- 
GitLab