From e80f463bd12aa530d8cc0a62e3847a200a87f47e Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Mon, 16 Sep 2024 09:03:17 +1000 Subject: [PATCH] Listening to changes in community write access In order to allow the showing and hiding of the input bar dynamically --- .../conversation/v2/ConversationActivityV2.kt | 3 +- .../conversation/v2/ConversationViewModel.kt | 29 +++++++++++++++++-- .../securesms/groups/OpenGroupManager.kt | 13 +++++++++ .../v2/ConversationViewModelTest.kt | 4 +-- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index d21574ec96..0ec98824b3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -710,7 +710,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // called from onCreate private fun setUpInputBar() { - binding.inputBar.isGone = viewModel.hidesInputBar() binding.inputBar.delegate = this binding.inputBarRecordingView.delegate = this // GIF button @@ -854,6 +853,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // Conversation should be deleted now, just go back finish() } + + binding.inputBar.isGone = uiState.hideInputBar } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt index b0a541a9e8..06515f40ca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt @@ -9,8 +9,12 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.session.libsession.database.MessageDataProvider @@ -29,6 +33,7 @@ import org.thoughtcrime.securesms.audio.AudioSlidePlayer import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MmsMessageRecord +import org.thoughtcrime.securesms.groups.OpenGroupManager import org.thoughtcrime.securesms.repository.ConversationRepository import java.util.UUID @@ -65,6 +70,8 @@ class ConversationViewModel( } } + private var communityWriteAccessJob: Job? = null + private var _openGroup: RetrieveOnce = RetrieveOnce { storage.getOpenGroup(threadId) } @@ -105,6 +112,23 @@ class ConversationViewModel( } } } + + // listen to community write access updates from this point + communityWriteAccessJob?.cancel() + communityWriteAccessJob = viewModelScope.launch { + OpenGroupManager.getCommunitiesWriteAccessFlow() + .map { it[openGroup?.server] } + .filterNotNull() + .collect{ + // update our community object + _openGroup.updateTo(openGroup?.copy(canWrite = it)) + // when we get an update on the write access of a community + // we need to update the input text accordingly + _uiState.update { + it.copy(hideInputBar = shouldHideInputBar()) + } + } + } } override fun onCleared() { @@ -267,7 +291,7 @@ class ConversationViewModel( * - We are dealing with a contact from a community (blinded recipient) that does not allow * requests form community members */ - fun hidesInputBar(): Boolean = openGroup?.canWrite == false || + private fun shouldHideInputBar(): Boolean = openGroup?.canWrite == false || blindedRecipient?.blocksCommunityMessageRequests == true fun legacyBannerRecipient(context: Context): Recipient? = recipient?.run { @@ -311,7 +335,8 @@ data class UiMessage(val id: Long, val message: String) data class ConversationUiState( val uiMessages: List = emptyList(), val isMessageRequestAccepted: Boolean? = null, - val conversationExists: Boolean + val conversationExists: Boolean, + val hideInputBar: Boolean = false ) data class RetrieveOnce(val retrieval: () -> T?) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt index b8f3ba8012..5fae172dde 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt @@ -4,6 +4,9 @@ import android.content.Context import android.widget.Toast import androidx.annotation.WorkerThread import com.squareup.phrase.Phrase +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import java.util.concurrent.Executors import network.loki.messenger.R import okhttp3.HttpUrl.Companion.toHttpUrlOrNull @@ -39,6 +42,9 @@ object OpenGroupManager { return true } + // flow holding information on write access for our current communities + private val _communityWriteAccess: MutableStateFlow> = MutableStateFlow(emptyMap()) + fun startPolling() { if (isPolling) { return } isPolling = true @@ -66,6 +72,8 @@ object OpenGroupManager { } } + fun getCommunitiesWriteAccessFlow() = _communityWriteAccess.asStateFlow() + @WorkerThread fun add(server: String, room: String, publicKey: String, context: Context): Pair { val openGroupID = "$server.$room" @@ -167,6 +175,11 @@ object OpenGroupManager { val openGroupID = "${openGroup.server}.${openGroup.room}" val threadID = GroupManager.getOpenGroupThreadID(openGroupID, context) threadDB.setOpenGroupChat(openGroup, threadID) + + // update write access for this community + val writeAccesses = _communityWriteAccess.value.toMutableMap() + writeAccesses[openGroup.server] = openGroup.canWrite + _communityWriteAccess.value = writeAccesses } fun isUserModerator(context: Context, groupId: String, standardPublicKey: String, blindedPublicKey: String? = null): Boolean { diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt index 1bd6a63c7f..936416d922 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt @@ -203,7 +203,7 @@ class ConversationViewModelTest: BaseViewModelTest() { @Test fun `local recipient should have input and no blinded recipient`() { whenever(recipient.isLocalNumber).thenReturn(true) - assertThat(viewModel.hidesInputBar(), equalTo(false)) + assertThat(viewModel.uiState.value.hideInputBar, equalTo(false)) assertThat(viewModel.blindedRecipient, nullValue()) } @@ -215,7 +215,7 @@ class ConversationViewModelTest: BaseViewModelTest() { } whenever(repository.maybeGetBlindedRecipient(recipient)).thenReturn(blinded) assertThat(viewModel.blindedRecipient, notNullValue()) - assertThat(viewModel.hidesInputBar(), equalTo(true)) + assertThat(viewModel.uiState.value.hideInputBar, equalTo(true)) } } \ No newline at end of file