From 42a536fef7750da848f644b3428a05fb8c53af6f Mon Sep 17 00:00:00 2001 From: SessionHero01 <180888785+SessionHero01@users.noreply.github.com> Date: Fri, 14 Feb 2025 09:04:20 +1100 Subject: [PATCH] Add the ability to re-create legacy group for unknown members (#944) --- .../securesms/groups/CreateGroupViewModel.kt | 14 +++---- .../groups/SelectContactsViewModel.kt | 40 ++++++++++++++----- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt index 27ab046fbb..3607119002 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/CreateGroupViewModel.kt @@ -22,7 +22,6 @@ import org.session.libsignal.utilities.AccountId import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.textSizeInBytes import org.thoughtcrime.securesms.database.GroupDatabase import org.thoughtcrime.securesms.dependencies.ConfigFactory -import javax.inject.Inject @HiltViewModel(assistedFactory = CreateGroupViewModel.Factory::class) @@ -68,12 +67,13 @@ class CreateGroupViewModel @AssistedInject constructor( mutableGroupName.value = group.title val myPublicKey = storage.getUserPublicKey() - selectContactsViewModel.selectAccountIDs( - group.members - .asSequence() - .filter { it.serialize() != myPublicKey } - .mapTo(mutableSetOf()) { AccountId(it.serialize()) } - ) + val accountIDs = group.members + .asSequence() + .filter { it.serialize() != myPublicKey } + .mapTo(mutableSetOf()) { AccountId(it.serialize()) } + + selectContactsViewModel.selectAccountIDs(accountIDs) + selectContactsViewModel.setManuallyAddedContacts(accountIDs) } } finally { mutableIsLoading.value = false diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/SelectContactsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/SelectContactsViewModel.kt index d7634abb6b..9702b81827 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/SelectContactsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/SelectContactsViewModel.kt @@ -10,6 +10,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel @@ -19,6 +20,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn @@ -43,6 +45,10 @@ class SelectContactsViewModel @AssistedInject constructor( // Input: The selected contact account IDs private val mutableSelectedContactAccountIDs = MutableStateFlow(emptySet()) + // Input: The manually added items to select from. This will be combined (and deduped) with the contacts + // the user has. This is useful for selecting contacts that are not in the user's contacts list. + private val mutableManuallyAddedContacts = MutableStateFlow(emptySet()) + // Output: The search query val searchQuery: StateFlow get() = mutableSearchQuery @@ -64,20 +70,30 @@ class SelectContactsViewModel @AssistedInject constructor( scope.cancel() } + @OptIn(ExperimentalCoroutinesApi::class) private fun observeContacts() = (configFactory.configUpdateNotifications as Flow) .debounce(100L) .onStart { emit(Unit) } - .map { - withContext(Dispatchers.Default) { - val allContacts = configFactory.withUserConfigs { configs -> - configs.contacts.all().filter { it.approvedMe } + .flatMapLatest { + mutableManuallyAddedContacts.map { manuallyAdded -> + withContext(Dispatchers.Default) { + val allContacts = + (configFactory.withUserConfigs { configs -> configs.contacts.all() } + .asSequence() + .map { AccountId(it.id) } + manuallyAdded) + + if (excludingAccountIDs.isEmpty()) { + allContacts.toSet() + } else { + allContacts.filterNotTo(mutableSetOf()) { it in excludingAccountIDs } + }.map { + Recipient.from( + appContext, + Address.fromSerialized(it.hexString), + false + ) + } } - - if (excludingAccountIDs.isEmpty()) { - allContacts - } else { - allContacts.filterNot { AccountId(it.id) in excludingAccountIDs } - }.map { Recipient.from(appContext, Address.fromSerialized(it.id), false) } } } @@ -102,6 +118,10 @@ class SelectContactsViewModel @AssistedInject constructor( .sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }) } + fun setManuallyAddedContacts(accountIDs: Set) { + mutableManuallyAddedContacts.value = accountIDs + } + fun onSearchQueryChanged(query: String) { mutableSearchQuery.value = query }