Add support for announcement groups.

This commit is contained in:
Greyson Parrelli
2021-07-23 16:22:08 -04:00
parent 1a56924a56
commit 25234496bf
74 changed files with 1109 additions and 208 deletions

View File

@@ -296,6 +296,17 @@ public final class GroupManager {
}
}
@WorkerThread
public static void applyAnnouncementGroupChange(@NonNull Context context,
@NonNull GroupId.V2 groupId,
@NonNull boolean isAnnouncementGroup)
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException, GroupChangeBusyException
{
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
editor.updateAnnouncementGroup(isAnnouncementGroup);
}
}
@WorkerThread
public static void cycleGroupLinkPassword(@NonNull Context context,
@NonNull GroupId.V2 groupId)

View File

@@ -336,6 +336,13 @@ final class GroupManagerV2 {
return commitChangeWithConflictResolution(groupOperations.createChangeMembershipRights(rightsToAccessControl(newRights)));
}
@WorkerThread
@NonNull GroupManager.GroupActionResult updateAnnouncementGroup(boolean isAnnouncementGroup)
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
return commitChangeWithConflictResolution(groupOperations.createAnnouncementGroupChange(isAnnouncementGroup));
}
@WorkerThread
@NonNull GroupManager.GroupActionResult updateGroupTitleDescriptionAndAvatar(@Nullable String title, @Nullable String description, @Nullable byte[] avatarBytes, boolean avatarChanged)
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
@@ -345,7 +352,7 @@ final class GroupManagerV2 {
: GroupChange.Actions.newBuilder();
if (description != null) {
change.setModifyDescription(groupOperations.createModifyGroupDescription(description));
change.setModifyDescription(groupOperations.createModifyGroupDescriptionAction(description));
}
if (avatarChanged) {

View File

@@ -129,6 +129,10 @@ public final class LiveGroup {
return Transformations.map(groupRecord, GroupDatabase.GroupRecord::getDescription);
}
public LiveData<Boolean> isAnnouncementGroup() {
return Transformations.map(groupRecord, GroupDatabase.GroupRecord::isAnnouncementGroup);
}
public LiveData<Recipient> getGroupRecipient() {
return recipient;
}

View File

@@ -11,14 +11,15 @@ import java.io.IOException;
public enum GroupChangeFailureReason {
NO_RIGHTS,
NOT_CAPABLE,
NOT_GV2_CAPABLE,
NOT_ANNOUNCEMENT_CAPABLE,
NOT_A_MEMBER,
BUSY,
NETWORK,
OTHER;
public static @NonNull GroupChangeFailureReason fromException(@NonNull Throwable e) {
if (e instanceof MembershipNotSuitableForV2Exception) return GroupChangeFailureReason.NOT_CAPABLE;
if (e instanceof MembershipNotSuitableForV2Exception) return GroupChangeFailureReason.NOT_GV2_CAPABLE;
if (e instanceof IOException) return GroupChangeFailureReason.NETWORK;
if (e instanceof GroupNotAMemberException) return GroupChangeFailureReason.NOT_A_MEMBER;
if (e instanceof GroupChangeBusyException) return GroupChangeFailureReason.BUSY;

View File

@@ -15,12 +15,13 @@ public final class GroupErrors {
}
switch (failureReason) {
case NO_RIGHTS : return R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this;
case NOT_CAPABLE : return R.string.ManageGroupActivity_not_capable;
case NOT_A_MEMBER: return R.string.ManageGroupActivity_youre_not_a_member_of_the_group;
case BUSY : return R.string.ManageGroupActivity_failed_to_update_the_group_please_retry_later;
case NETWORK : return R.string.ManageGroupActivity_failed_to_update_the_group_due_to_a_network_error_please_retry_later;
default : return R.string.ManageGroupActivity_failed_to_update_the_group;
case NO_RIGHTS : return R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this;
case NOT_GV2_CAPABLE : return R.string.ManageGroupActivity_not_capable;
case NOT_ANNOUNCEMENT_CAPABLE: return R.string.ManageGroupActivity_not_announcement_capable;
case NOT_A_MEMBER : return R.string.ManageGroupActivity_youre_not_a_member_of_the_group;
case BUSY : return R.string.ManageGroupActivity_failed_to_update_the_group_please_retry_later;
case NETWORK : return R.string.ManageGroupActivity_failed_to_update_the_group_due_to_a_network_error_please_retry_later;
default : return R.string.ManageGroupActivity_failed_to_update_the_group;
}
}
}

View File

@@ -23,10 +23,12 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class AddMembersActivity extends PushContactSelectionActivity {
public static final String GROUP_ID = "group_id";
public static final String GROUP_ID = "group_id";
public static final String ANNOUNCEMENT_GROUP = "announcement_group";
private View done;
private AddMembersViewModel viewModel;
@@ -36,10 +38,12 @@ public class AddMembersActivity extends PushContactSelectionActivity {
int displayModeFlags,
int selectionWarning,
int selectionLimit,
boolean isAnnouncementGroup,
@NonNull List<RecipientId> membersWithoutSelf) {
Intent intent = new Intent(context, AddMembersActivity.class);
intent.putExtra(AddMembersActivity.GROUP_ID, groupId.toString());
intent.putExtra(GROUP_ID, groupId.toString());
intent.putExtra(ANNOUNCEMENT_GROUP, isAnnouncementGroup);
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayModeFlags);
intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, new SelectionLimits(selectionWarning, selectionLimit));
intent.putParcelableArrayListExtra(ContactSelectionListFragment.CURRENT_SELECTION, new ArrayList<>(membersWithoutSelf));
@@ -75,10 +79,11 @@ public class AddMembersActivity extends PushContactSelectionActivity {
}
@Override
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
public void onBeforeContactSelected(Optional<RecipientId> recipientId, String number, Consumer<Boolean> callback) {
if (getGroupId().isV1() && recipientId.isPresent() && !Recipient.resolved(recipientId.get()).hasE164()) {
Toast.makeText(this, R.string.AddMembersActivity__this_person_cant_be_added_to_legacy_groups, Toast.LENGTH_SHORT).show();
return false;
callback.accept(false);
return;
}
if (contactsFragment.hasQueryFilter()) {
@@ -87,7 +92,7 @@ public class AddMembersActivity extends PushContactSelectionActivity {
enableDone();
return true;
callback.accept(true);
}
@Override
@@ -125,6 +130,10 @@ public class AddMembersActivity extends PushContactSelectionActivity {
return GroupId.parseOrThrow(getIntent().getStringExtra(GROUP_ID));
}
private boolean isAnnouncementGroup() {
return getIntent().getBooleanExtra(ANNOUNCEMENT_GROUP, false);
}
private void displayAlertMessage(@NonNull AddMembersViewModel.AddMemberDialogMessageState state) {
Recipient recipient = Util.firstNonNull(state.getRecipient(), Recipient.UNKNOWN);

View File

@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
/**
* Group selection activity, will add a single member to selected groups.
@@ -112,7 +113,7 @@ public final class AddToGroupsActivity extends ContactSelectionActivity {
}
@Override
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
public void onBeforeContactSelected(Optional<RecipientId> recipientId, String number, Consumer<Boolean> callback) {
if (contactsFragment.isMulti()) {
throw new UnsupportedOperationException("Not yet built to handle multi-select.");
// if (contactsFragment.hasQueryFilter()) {
@@ -128,7 +129,7 @@ public final class AddToGroupsActivity extends ContactSelectionActivity {
}
}
return true;
callback.accept(true);
}
@Override

View File

@@ -39,6 +39,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
public class CreateGroupActivity extends ContactSelectionActivity {
@@ -97,14 +98,14 @@ public class CreateGroupActivity extends ContactSelectionActivity {
}
@Override
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
public void onBeforeContactSelected(Optional<RecipientId> recipientId, String number, Consumer<Boolean> callback) {
if (contactsFragment.hasQueryFilter()) {
getContactFilterView().clear();
}
shrinkSkip();
return true;
callback.accept(true);
}
@Override