[SES-3270] - Group invitation tweaks (#933)

pull/1709/head
SessionHero01 3 months ago committed by GitHub
parent 9755d252a6
commit b73520cb24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -82,6 +82,7 @@ import org.thoughtcrime.securesms.dependencies.PollerFactory;
import org.thoughtcrime.securesms.emoji.EmojiSource; import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.groups.OpenGroupManager; import org.thoughtcrime.securesms.groups.OpenGroupManager;
import org.thoughtcrime.securesms.groups.handler.AdminStateSync; import org.thoughtcrime.securesms.groups.handler.AdminStateSync;
import org.thoughtcrime.securesms.groups.handler.CleanupInvitationHandler;
import org.thoughtcrime.securesms.groups.handler.DestroyedGroupSync; import org.thoughtcrime.securesms.groups.handler.DestroyedGroupSync;
import org.thoughtcrime.securesms.groups.handler.RemoveGroupMemberHandler; import org.thoughtcrime.securesms.groups.handler.RemoveGroupMemberHandler;
import org.thoughtcrime.securesms.home.HomeActivity; import org.thoughtcrime.securesms.home.HomeActivity;
@ -173,6 +174,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
@Inject EmojiSearchDatabase emojiSearchDb; @Inject EmojiSearchDatabase emojiSearchDb;
@Inject LegacyClosedGroupPollerV2 legacyClosedGroupPollerV2; @Inject LegacyClosedGroupPollerV2 legacyClosedGroupPollerV2;
@Inject LegacyGroupDeprecationManager legacyGroupDeprecationManager; @Inject LegacyGroupDeprecationManager legacyGroupDeprecationManager;
@Inject CleanupInvitationHandler cleanupInvitationHandler;
public volatile boolean isAppVisible; public volatile boolean isAppVisible;
public String KEYGUARD_LOCK_TAG = NonTranslatableStringConstants.APP_NAME + ":KeyguardLock"; public String KEYGUARD_LOCK_TAG = NonTranslatableStringConstants.APP_NAME + ":KeyguardLock";
@ -293,6 +295,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
removeGroupMemberHandler.start(); removeGroupMemberHandler.start();
destroyedGroupSync.start(); destroyedGroupSync.start();
adminStateSync.start(); adminStateSync.start();
cleanupInvitationHandler.start();
// add our shortcut debug menu if we are not in a release build // add our shortcut debug menu if we are not in a release build
if (BuildConfig.BUILD_TYPE != "release") { if (BuildConfig.BUILD_TYPE != "release") {

@ -240,7 +240,7 @@ class ConfigFactory @Inject constructor(
if (recreateConfigInstances) { if (recreateConfigInstances) {
synchronized(groupConfigs) { synchronized(groupConfigs) {
groupConfigs.remove(groupId) groupConfigs.remove(groupId)
} }?.second?.dumpIfNeeded(clock)
} }
val (lock, configs) = ensureGroupConfigsInitialized(groupId) val (lock, configs) = ensureGroupConfigsInitialized(groupId)

@ -79,13 +79,16 @@ class EditGroupViewModel @AssistedInject constructor(
get() = groupInfo.value?.second?.mapTo(hashSetOf()) { it.accountId }.orEmpty() get() = groupInfo.value?.second?.mapTo(hashSetOf()) { it.accountId }.orEmpty()
fun onContactSelected(contacts: Set<AccountId>) { fun onContactSelected(contacts: Set<AccountId>) {
performGroupOperation(errorMessage = { err -> performGroupOperation(
if (err is GroupInviteException) { showLoading = false,
err.format(context, storage).toString() errorMessage = { err ->
} else { if (err is GroupInviteException) {
null err.format(context, storage).toString()
} else {
null
}
} }
}) { ) {
groupManager.inviteMembers( groupManager.inviteMembers(
groupId, groupId,
contacts.toList(), contacts.toList(),
@ -99,13 +102,13 @@ class EditGroupViewModel @AssistedInject constructor(
} }
fun onPromoteContact(memberSessionId: AccountId) { fun onPromoteContact(memberSessionId: AccountId) {
performGroupOperation { performGroupOperation(showLoading = false) {
groupManager.promoteMember(groupId, listOf(memberSessionId)) groupManager.promoteMember(groupId, listOf(memberSessionId))
} }
} }
fun onRemoveContact(contactSessionId: AccountId, removeMessages: Boolean) { fun onRemoveContact(contactSessionId: AccountId, removeMessages: Boolean) {
performGroupOperation { performGroupOperation(showLoading = false) {
groupManager.removeMembers( groupManager.removeMembers(
groupAccountId = groupId, groupAccountId = groupId,
removedMembers = listOf(contactSessionId), removedMembers = listOf(contactSessionId),
@ -170,10 +173,13 @@ class EditGroupViewModel @AssistedInject constructor(
* This is a helper function that encapsulates the common error handling and progress tracking. * This is a helper function that encapsulates the common error handling and progress tracking.
*/ */
private fun performGroupOperation( private fun performGroupOperation(
showLoading: Boolean = true,
errorMessage: ((Throwable) -> String?)? = null, errorMessage: ((Throwable) -> String?)? = null,
operation: suspend () -> Unit) { operation: suspend () -> Unit) {
viewModelScope.launch { viewModelScope.launch {
mutableInProgress.value = true if (showLoading) {
mutableInProgress.value = true
}
// We need to use GlobalScope here because we don't want // We need to use GlobalScope here because we don't want
// any group operation to be cancelled when the view model is cleared. // any group operation to be cancelled when the view model is cleared.
@ -188,7 +194,9 @@ class EditGroupViewModel @AssistedInject constructor(
mutableError.value = errorMessage?.invoke(e) mutableError.value = errorMessage?.invoke(e)
?: context.getString(R.string.errorUnknown) ?: context.getString(R.string.errorUnknown)
} finally { } finally {
mutableInProgress.value = false if (showLoading) {
mutableInProgress.value = false
}
} }
} }
} }

@ -276,6 +276,9 @@ class GroupManagerV2Impl @Inject constructor(
// Make sure every request is successful // Make sure every request is successful
response.requireAllRequestsSuccessful("Failed to invite members") response.requireAllRequestsSuccessful("Failed to invite members")
// Wait for the group configs to be pushed
configFactory.waitUntilGroupConfigsPushed(group)
} catch (e: Exception) { } catch (e: Exception) {
// Update every member's status to "invite failed" and return group name // Update every member's status to "invite failed" and return group name
val groupName = configFactory.withMutableGroupConfigs(group) { configs -> val groupName = configFactory.withMutableGroupConfigs(group) { configs ->

@ -0,0 +1,54 @@
package org.thoughtcrime.securesms.groups.handler
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import network.loki.messenger.libsession_util.allWithStatus
import network.loki.messenger.libsession_util.util.GroupMember
import org.session.libsession.messaging.groups.GroupScope
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.TextSecurePreferences
import javax.inject.Inject
/**
* This handler is responsible for cleaning up the intermediate states that are created when
* sending invitations to join a group. This clean-up is necessary because the app could crash
* or being killed before the invitation is sent, and we don't want to leave the group member in a
* "pending" state while it's not really pending.
*
* This is achieved by checking the group members and marking the "pending" state as "failed"
* after the app is started, and only done once on every app process.
*/
class CleanupInvitationHandler @Inject constructor(
private val prefs: TextSecurePreferences,
private val configFactory: ConfigFactoryProtocol,
private val groupScope: GroupScope
) {
fun start() {
GlobalScope.launch {
// Wait for the local number to be available
prefs.watchLocalNumber().first { it != null }
val allGroups = configFactory.withUserConfigs {
it.userGroups.allClosedGroupInfo()
}
allGroups
.asSequence()
.filter { !it.kicked && !it.destroyed && it.hasAdminKey() }
.forEach { group ->
groupScope.launch(group.groupAccountId, debugName = "CleanupInvitationHandler") {
configFactory.withMutableGroupConfigs(group.groupAccountId) { configs ->
configs.groupMembers
.allWithStatus()
.filter { it.second == GroupMember.Status.INVITE_SENDING }
.forEach { (member, _) ->
member.setInviteFailed()
configs.groupMembers.set(member)
}
}
}
}
}
}
}
Loading…
Cancel
Save