Improve GV2 Invitation revoke experience.

This commit is contained in:
Alan Evans
2020-08-06 15:06:15 -03:00
committed by Greyson Parrelli
parent c8ed0b19f0
commit 810ccf8e94
9 changed files with 241 additions and 25 deletions

View File

@@ -297,7 +297,13 @@ final class GroupsV2UpdateMessageProducer {
boolean newMemberIsYou = invitee.getUuid().equals(selfUuidBytes);
if (newMemberIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_were_invited_to_the_group)));
UUID uuid = UuidUtil.fromByteStringOrUnknown(invitee.getAddedByUuid());
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_were_invited_to_the_group)));
} else {
updates.add(updateDescription(invitee.getAddedByUuid(), editor -> context.getString(R.string.MessageRecord_s_invited_you_to_the_group, editor)));
}
} else {
notYouInviteCount++;
}
@@ -320,6 +326,8 @@ final class GroupsV2UpdateMessageProducer {
} else {
updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group)));
}
} else if (invitee.getUuid().equals(selfUuidBytes)) {
updates.add(updateDescription(change.getEditor(), editor -> context.getString(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, editor)));
} else {
notDeclineCount++;
}
@@ -342,7 +350,7 @@ final class GroupsV2UpdateMessageProducer {
boolean inviteeWasYou = invitee.getUuid().equals(selfUuidBytes);
if (inviteeWasYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_your_invitation_to_the_group_was_revoked)));
updates.add(updateDescription(context.getString(R.string.MessageRecord_an_admin_revoked_your_invitation_to_the_group)));
} else {
notDeclineCount++;
}

View File

@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.messagerequests;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import androidx.core.util.Consumer;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
@@ -67,15 +68,29 @@ final class MessageRequestRepository {
}
void getMessageRequestState(@NonNull Recipient recipient, long threadId, @NonNull Consumer<MessageRequestState> state) {
executor.execute(() -> {
if (!RecipientUtil.isMessageRequestAccepted(context, threadId)) {
state.accept(MessageRequestState.UNACCEPTED);
} else if (RecipientUtil.isPreMessageRequestThread(context, threadId) && !RecipientUtil.isLegacyProfileSharingAccepted(recipient)) {
state.accept(MessageRequestState.LEGACY);
} else {
state.accept(MessageRequestState.ACCEPTED);
executor.execute(() -> state.accept(findMessageRequestState(recipient, threadId)));
}
@WorkerThread
private MessageRequestState findMessageRequestState(@NonNull Recipient recipient, long threadId) {
if (!RecipientUtil.isMessageRequestAccepted(context, threadId)) {
if (recipient.isGroup()) {
GroupDatabase.MemberLevel memberLevel = DatabaseFactory.getGroupDatabase(context)
.getGroup(recipient.getId())
.transform(g -> g.memberLevel(Recipient.self()))
.or(GroupDatabase.MemberLevel.NOT_A_MEMBER);
if (memberLevel == GroupDatabase.MemberLevel.NOT_A_MEMBER) {
return MessageRequestState.NOT_REQUIRED;
}
}
});
return MessageRequestState.REQUIRED;
} else if (RecipientUtil.isPreMessageRequestThread(context, threadId) && !RecipientUtil.isLegacyProfileSharingAccepted(recipient)) {
return MessageRequestState.LEGACY;
} else {
return MessageRequestState.NOT_REQUIRED;
}
}
void acceptMessageRequest(@NonNull LiveRecipient liveRecipient,
@@ -218,6 +233,19 @@ final class MessageRequestRepository {
}
enum MessageRequestState {
ACCEPTED, UNACCEPTED, LEGACY
/**
* Message request permission does not need to be gained at this time.
* <p>
* Either:
* - Explicit message request has been accepted, or;
* - Did not need to be shown because they are a contact etc, or;
* - It's a group that they are no longer in or invited to.
*/
NOT_REQUIRED,
/** Explicit message request permission is required. */
REQUIRED,
LEGACY
}
}

View File

@@ -161,10 +161,10 @@ public class MessageRequestViewModel extends ViewModel {
repository.getMessageRequestState(recipient, threadId, accepted -> {
switch (accepted) {
case ACCEPTED:
case NOT_REQUIRED:
displayState.postValue(DisplayState.DISPLAY_NONE);
break;
case UNACCEPTED:
case REQUIRED:
displayState.postValue(DisplayState.DISPLAY_MESSAGE_REQUEST);
break;
case LEGACY:

View File

@@ -168,6 +168,7 @@ public final class MessageGroupContext {
memberUuids.addAll(DecryptedGroupUtil.membersToUuidList(decryptedGroupV2Context.getGroupState().getMembersList()));
memberUuids.addAll(DecryptedGroupUtil.pendingToUuidList(decryptedGroupV2Context.getGroupState().getPendingMembersList()));
memberUuids.addAll(DecryptedGroupUtil.removedMembersUuidList(decryptedGroupV2Context.getChange()));
memberUuids.addAll(DecryptedGroupUtil.removedPendingMembersUuidList(decryptedGroupV2Context.getChange()));
return UuidUtil.filterKnown(memberUuids);
}

View File

@@ -865,7 +865,8 @@
</plurals>
<string name="MessageRecord_someone_declined_an_invitation_to_the_group">Someone declined an invitation to the group.</string>
<string name="MessageRecord_you_declined_the_invitation_to_the_group">You declined the invitation to the group.</string>
<string name="MessageRecord_your_invitation_to_the_group_was_revoked">Your invitation to the group was revoked.</string>
<string name="MessageRecord_s_revoked_your_invitation_to_the_group">%1$s revoked your invitation to the group.</string>
<string name="MessageRecord_an_admin_revoked_your_invitation_to_the_group">An admin revoked your invitation to the group.</string>
<plurals name="MessageRecord_d_invitations_were_revoked">
<item quantity="one">An invitation to the group was revoked.</item>
<item quantity="other">%1$d invitations to the group were revoked.</item>

View File

@@ -391,7 +391,16 @@ public final class GroupsV2UpdateMessageProducerTest {
}
@Test
public void unknown_invited_you() {
public void unknown_editor_but_known_invitee_invited_you() {
DecryptedGroupChange change = changeByUnknown()
.inviteBy(you, alice)
.build();
assertThat(describeChange(change), is(singletonList("Alice invited you to the group.")));
}
@Test
public void unknown_editor_and_unknown_inviter_invited_you() {
DecryptedGroupChange change = changeByUnknown()
.invite(you)
.build();
@@ -430,6 +439,18 @@ public final class GroupsV2UpdateMessageProducerTest {
assertThat(describeChange(change), is(Arrays.asList("You were invited to the group.", "3 people were invited to the group.")));
}
@Test
public void unknown_editor_invited_3_persons_and_you_inviter_known() {
DecryptedGroupChange change = changeByUnknown()
.invite(alice)
.inviteBy(you, bob)
.invite(UUID.randomUUID())
.invite(UUID.randomUUID())
.build();
assertThat(describeChange(change), is(Arrays.asList("Bob invited you to the group.", "3 people were invited to the group.")));
}
// Member invitation revocation
@Test
@@ -494,7 +515,7 @@ public final class GroupsV2UpdateMessageProducerTest {
.uninvite(you)
.build();
assertThat(describeChange(change), is(singletonList("Your invitation to the group was revoked.")));
assertThat(describeChange(change), is(singletonList("An admin revoked your invitation to the group.")));
}
@Test
@@ -525,7 +546,16 @@ public final class GroupsV2UpdateMessageProducerTest {
.uninvite(UUID.randomUUID())
.build();
assertThat(describeChange(change), is(Arrays.asList("Your invitation to the group was revoked.", "3 invitations to the group were revoked.")));
assertThat(describeChange(change), is(Arrays.asList("An admin revoked your invitation to the group.", "3 invitations to the group were revoked.")));
}
@Test
public void your_invite_was_revoked_by_known_member() {
DecryptedGroupChange change = changeBy(bob)
.uninvite(you)
.build();
assertThat(describeChange(change), is(singletonList("Bob revoked your invitation to the group.")));
}
// Promote pending members

View File

@@ -72,8 +72,13 @@ public final class ChangeBuilder {
}
public ChangeBuilder invite(@NonNull UUID potentialMember) {
return inviteBy(potentialMember, UuidUtil.UNKNOWN_UUID);
}
public ChangeBuilder inviteBy(@NonNull UUID potentialMember, @NonNull UUID inviter) {
builder.addNewPendingMembers(DecryptedPendingMember.newBuilder()
.setUuid(UuidUtil.toByteString(potentialMember)));
.setUuid(UuidUtil.toByteString(potentialMember))
.setAddedByUuid(UuidUtil.toByteString(inviter)));
return this;
}