Add block request action button to collapsed join request events.
This commit is contained in:
parent
130d5a8945
commit
d3049a3433
11 changed files with 188 additions and 5 deletions
|
@ -94,6 +94,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable,
|
|||
void onChangeNumberUpdateContact(@NonNull Recipient recipient);
|
||||
void onCallToAction(@NonNull String action);
|
||||
void onDonateClicked();
|
||||
void onBlockJoinRequest(@NonNull Recipient recipient);
|
||||
|
||||
/** @return true if handled, false if you want to let the normal url handling continue */
|
||||
boolean onUrlClicked(@NonNull String url);
|
||||
|
|
|
@ -177,6 +177,7 @@ class ConversationSettingsRepository(
|
|||
val groupActionResult = GroupManager.addMembers(context, groupId.requirePush(), selected)
|
||||
GroupAddMembersResult.Success(groupActionResult.addedMemberCount, Recipient.resolvedList(groupActionResult.invitedMembers))
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "Failure to add member", e)
|
||||
GroupAddMembersResult.Failure(GroupChangeFailureReason.fromException(e))
|
||||
}
|
||||
)
|
||||
|
|
|
@ -115,10 +115,12 @@ import org.thoughtcrime.securesms.giph.mp4.GiphyMp4ProjectionPlayerHolder;
|
|||
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4ProjectionRecycler;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
|
||||
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.invite.GroupLinkInviteFriendsBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupDescriptionDialog;
|
||||
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationInfoBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.groups.v2.GroupDescriptionUtil;
|
||||
import org.thoughtcrime.securesms.groups.v2.GroupManagementRepository;
|
||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
|
@ -151,6 +153,7 @@ import org.thoughtcrime.securesms.stickers.StickerPackPreviewActivity;
|
|||
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.HtmlUtil;
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable;
|
||||
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
||||
import org.thoughtcrime.securesms.util.RemoteDeleteUtil;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
|
@ -236,6 +239,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
private Colorizer colorizer;
|
||||
private ConversationUpdateTick conversationUpdateTick;
|
||||
private MultiselectItemDecoration multiselectItemDecoration;
|
||||
private LifecycleDisposable lifecycleDisposable;
|
||||
|
||||
public static void prepare(@NonNull Context context) {
|
||||
FrameLayout parent = new FrameLayout(context);
|
||||
|
@ -322,6 +326,9 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
|
||||
giphyMp4ProjectionRecycler = initializeGiphyMp4();
|
||||
|
||||
lifecycleDisposable = new LifecycleDisposable();
|
||||
lifecycleDisposable.bindTo(getViewLifecycleOwner());
|
||||
|
||||
this.groupViewModel = new ViewModelProvider(getParentFragment(), new ConversationGroupViewModel.Factory()).get(ConversationGroupViewModel.class);
|
||||
this.messageCountsViewModel = new ViewModelProvider(getParentFragment()).get(MessageCountsViewModel.class);
|
||||
this.conversationViewModel = new ViewModelProvider(getParentFragment(), new ConversationViewModel.Factory()).get(ConversationViewModel.class);
|
||||
|
@ -1862,6 +1869,15 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
startActivity(AppSettingsActivity.subscriptions(requireContext()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockJoinRequest(@NonNull Recipient recipient) {
|
||||
new MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.ConversationFragment__block_request)
|
||||
.setMessage(getString(R.string.ConversationFragment__s_will_not_be_able_to_join_or_request_to_join_this_group_via_the_group_link, recipient.getDisplayName(requireContext())))
|
||||
.setNegativeButton(R.string.ConversationFragment__cancel, null)
|
||||
.setPositiveButton(R.string.ConversationFragment__block_request_button, (d, w) -> handleBlockJoinRequest(recipient))
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshList() {
|
||||
|
@ -1892,6 +1908,18 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
|
||||
}
|
||||
|
||||
private void handleBlockJoinRequest(@NonNull Recipient recipient) {
|
||||
lifecycleDisposable.add(
|
||||
groupViewModel.blockJoinRequests(ConversationFragment.this.recipient.get(), recipient)
|
||||
.subscribe(result -> {
|
||||
if (result instanceof GroupManagementRepository.GroupManagementResult.Failure) {
|
||||
int failureReason = GroupErrors.getUserDisplayMessage(((GroupManagementRepository.GroupManagementResult.Failure) result).getReason());
|
||||
Toast.makeText(requireContext(), failureReason, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private final class CheckExpirationDataObserver extends RecyclerView.AdapterDataObserver {
|
||||
@Override
|
||||
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.thoughtcrime.securesms.groups.GroupManager;
|
|||
import org.thoughtcrime.securesms.groups.GroupsV1MigrationUtil;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.invite.GroupLinkInviteFriendsBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.groups.v2.GroupManagementRepository;
|
||||
import org.thoughtcrime.securesms.groups.v2.GroupManagementRepository.GroupManagementResult;
|
||||
import org.thoughtcrime.securesms.profiles.spoofing.ReviewRecipient;
|
||||
import org.thoughtcrime.securesms.profiles.spoofing.ReviewUtil;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
@ -38,6 +40,9 @@ import java.io.IOException;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
final class ConversationGroupViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<Recipient> liveRecipient;
|
||||
|
@ -46,11 +51,13 @@ final class ConversationGroupViewModel extends ViewModel {
|
|||
private final LiveData<Integer> actionableRequestingMembers;
|
||||
private final LiveData<ReviewState> reviewState;
|
||||
private final LiveData<List<RecipientId>> gv1MigrationSuggestions;
|
||||
private final GroupManagementRepository groupManagementRepository;
|
||||
|
||||
private boolean firstTimeInviteFriendsTriggered;
|
||||
|
||||
private ConversationGroupViewModel() {
|
||||
this.liveRecipient = new MutableLiveData<>();
|
||||
this.liveRecipient = new MutableLiveData<>();
|
||||
this.groupManagementRepository = new GroupManagementRepository();
|
||||
|
||||
LiveData<GroupRecord> groupRecord = LiveDataUtil.mapAsync(liveRecipient, ConversationGroupViewModel::getGroupRecordForRecipient);
|
||||
LiveData<List<Recipient>> duplicates = LiveDataUtil.mapAsync(groupRecord, record -> {
|
||||
|
@ -213,6 +220,11 @@ final class ConversationGroupViewModel extends ViewModel {
|
|||
GroupLinkInviteFriendsBottomSheetDialogFragment.show(supportFragmentManager, groupId);
|
||||
}
|
||||
|
||||
public Single<GroupManagementResult> blockJoinRequests(@NonNull Recipient groupRecipient, @NonNull Recipient recipient) {
|
||||
return groupManagementRepository.blockJoinRequests(groupRecipient.requireGroupId().requireV2(), recipient)
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
static final class ReviewState {
|
||||
|
||||
private static final ReviewState EMPTY = new ReviewState(null, Recipient.UNKNOWN, 0);
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
|
|||
import org.thoughtcrime.securesms.database.model.LiveUpdateMessage;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.UpdateDescription;
|
||||
import org.thoughtcrime.securesms.groups.LiveGroup;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
|
@ -85,6 +86,7 @@ public final class ConversationUpdateItem extends FrameLayout
|
|||
private final PresentOnChange presentOnChange = new PresentOnChange();
|
||||
private final RecipientObserverManager senderObserver = new RecipientObserverManager(presentOnChange);
|
||||
private final RecipientObserverManager groupObserver = new RecipientObserverManager(presentOnChange);
|
||||
private final GroupDataManager groupData = new GroupDataManager(presentOnChange);
|
||||
|
||||
public ConversationUpdateItem(Context context) {
|
||||
super(context);
|
||||
|
@ -153,8 +155,9 @@ public final class ConversationUpdateItem extends FrameLayout
|
|||
|
||||
senderObserver.observe(lifecycleOwner, messageRecord.getIndividualRecipient());
|
||||
|
||||
if (conversationRecipient.isActiveGroup() && conversationMessage.getMessageRecord().isGroupCall()) {
|
||||
if (conversationRecipient.isActiveGroup() && (conversationMessage.getMessageRecord().isGroupCall() || conversationMessage.getMessageRecord().isCollapsedGroupV2JoinUpdate())) {
|
||||
groupObserver.observe(lifecycleOwner, conversationRecipient);
|
||||
groupData.observe(lifecycleOwner, conversationRecipient);
|
||||
} else {
|
||||
groupObserver.observe(lifecycleOwner, null);
|
||||
}
|
||||
|
@ -269,6 +272,47 @@ public final class ConversationUpdateItem extends FrameLayout
|
|||
}
|
||||
}
|
||||
|
||||
static final class GroupDataManager {
|
||||
|
||||
private final Observer<Recipient> recipientObserver;
|
||||
private final Observer<Boolean> isSelfAdminSetter;
|
||||
|
||||
private LiveGroup liveGroup;
|
||||
private LiveData<Boolean> liveIsSelfAdmin;
|
||||
private boolean isSelfAdmin;
|
||||
private Recipient conversationRecipient;
|
||||
|
||||
GroupDataManager(@NonNull Observer<Recipient> observer) {
|
||||
this.recipientObserver = observer;
|
||||
this.isSelfAdminSetter = isSelfAdmin -> {
|
||||
this.isSelfAdmin = isSelfAdmin;
|
||||
recipientObserver.onChanged(conversationRecipient);
|
||||
};
|
||||
}
|
||||
|
||||
public void observe(@NonNull LifecycleOwner lifecycleOwner, @Nullable Recipient recipient) {
|
||||
if (liveGroup != null) {
|
||||
liveIsSelfAdmin.removeObserver(isSelfAdminSetter);
|
||||
liveIsSelfAdmin = null;
|
||||
}
|
||||
|
||||
if (recipient != null) {
|
||||
conversationRecipient = recipient;
|
||||
liveGroup = new LiveGroup(recipient.requireGroupId());
|
||||
liveIsSelfAdmin = liveGroup.isSelfAdmin();
|
||||
|
||||
liveIsSelfAdmin.observe(lifecycleOwner, isSelfAdminSetter);
|
||||
} else {
|
||||
conversationRecipient = null;
|
||||
liveGroup = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSelfAdmin() {
|
||||
return isSelfAdmin;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MultiselectPart getMultiselectPartForLatestTouch() {
|
||||
return conversationMessage.getMultiselectCollection().asSingle().getSinglePart();
|
||||
|
@ -427,6 +471,14 @@ public final class ConversationUpdateItem extends FrameLayout
|
|||
eventListener.onChangeNumberUpdateContact(conversationMessage.getMessageRecord().getIndividualRecipient());
|
||||
}
|
||||
});
|
||||
} else if (conversationMessage.getMessageRecord().isCollapsedGroupV2JoinUpdate() && groupData.isSelfAdmin()) {
|
||||
actionButton.setText(R.string.ConversationUpdateItem_block_request);
|
||||
actionButton.setVisibility(VISIBLE);
|
||||
actionButton.setOnClickListener(v -> {
|
||||
if (batchSelected.isEmpty() && eventListener != null) {
|
||||
eventListener.onBlockJoinRequest(conversationMessage.getMessageRecord().getIndividualRecipient());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
actionButton.setVisibility(GONE);
|
||||
actionButton.setOnClickListener(null);
|
||||
|
|
|
@ -73,8 +73,6 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import kotlin.collections.CollectionsKt;
|
||||
|
||||
/**
|
||||
* The base class for message record models that are displayed in
|
||||
* conversations, as opposed to models that are displayed in a thread list.
|
||||
|
@ -423,6 +421,15 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isCollapsedGroupV2JoinUpdate() {
|
||||
DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context();
|
||||
if (decryptedGroupV2Context != null && decryptedGroupV2Context.hasChange()) {
|
||||
DecryptedGroupChange change = decryptedGroupV2Context.getChange();
|
||||
return change.getNewRequestingMembersCount() > 0 && change.getDeleteRequestingMembersCount() > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static @NonNull String createNewContextWithAppendedDeleteJoinRequest(@NonNull MessageRecord messageRecord, int revision, @NonNull ByteString id) {
|
||||
DecryptedGroupV2Context decryptedGroupV2Context = messageRecord.getDecryptedGroupV2Context();
|
||||
|
||||
|
|
|
@ -1207,7 +1207,7 @@ final class GroupManagerV2 {
|
|||
|
||||
DecryptedGroupChange plainGroupChange = groupMutation.getGroupChange();
|
||||
|
||||
if (plainGroupChange != null && DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(plainGroupChange)) {
|
||||
if (plainGroupChange != null && DecryptedGroupUtil.changeIsSilent(plainGroupChange)) {
|
||||
if (sendToMembers) {
|
||||
ApplicationDependencies.getJobManager().add(PushGroupSilentUpdateSendJob.create(context, groupId, groupMutation.getNewGroupState(), outgoingMessage));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.thoughtcrime.securesms.groups.v2
|
||||
|
||||
import android.content.Context
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.groups.GroupChangeException
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.groups.GroupManager
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import java.io.IOException
|
||||
|
||||
private val TAG: String = Log.tag(GroupManagementRepository::class.java)
|
||||
|
||||
/**
|
||||
* Single source repository for managing groups.
|
||||
*/
|
||||
class GroupManagementRepository @JvmOverloads constructor(private val context: Context = ApplicationDependencies.getApplication()) {
|
||||
|
||||
fun blockJoinRequests(groupId: GroupId.V2, recipient: Recipient): Single<GroupManagementResult> {
|
||||
return Single.fromCallable {
|
||||
try {
|
||||
GroupManager.ban(context, groupId, recipient.id)
|
||||
GroupManagementResult.Success
|
||||
} catch (e: GroupChangeException) {
|
||||
Log.w(TAG, e)
|
||||
GroupManagementResult.Failure(GroupChangeFailureReason.fromException(e))
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, e)
|
||||
GroupManagementResult.Failure(GroupChangeFailureReason.fromException(e))
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
sealed class GroupManagementResult {
|
||||
object Success : GroupManagementResult()
|
||||
data class Failure(val reason: GroupChangeFailureReason) : GroupManagementResult()
|
||||
}
|
||||
}
|
|
@ -612,6 +612,8 @@ public class GroupsV2StateProcessor {
|
|||
for (LocalGroupLogEntry entry : processedLogEntries) {
|
||||
if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(entry.getChange()) && !DecryptedGroupUtil.changeIsEmpty(entry.getChange())) {
|
||||
Log.d(TAG, "Skipping profile key changes only update message");
|
||||
} if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(entry.getChange())) {
|
||||
Log.d(TAG, "Skipping ban changes only update message");
|
||||
} else {
|
||||
if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmpty(entry.getChange()) && previousGroupState != null) {
|
||||
Log.w(TAG, "Empty group update message seen. Not inserting.");
|
||||
|
|
|
@ -367,6 +367,14 @@
|
|||
<string name="ConversationFragment_your_safety_number_with_s_changed_likey_because_they_reinstalled_signal">Your safety number with %s changed, likely because they reinstalled Signal or changed devices. Tap Verify to confirm the new safety number. This is optional.</string>
|
||||
<!-- Message shown to indicate which notification profile is on/active -->
|
||||
<string name="ConversationFragment__s_on">%1$s on</string>
|
||||
<!-- Dialog title for block group link join requests -->
|
||||
<string name="ConversationFragment__block_request">Block request?</string>
|
||||
<!-- Dialog message for block group link join requests -->
|
||||
<string name="ConversationFragment__s_will_not_be_able_to_join_or_request_to_join_this_group_via_the_group_link">%1$s will not be able to join or request to join this group via the group link. They can still be added to the group manually.</string>
|
||||
<!-- Dialog confirm block request button -->
|
||||
<string name="ConversationFragment__block_request_button">Block request</string>
|
||||
<!-- Dialog cancel block request button -->
|
||||
<string name="ConversationFragment__cancel">Cancel</string>
|
||||
|
||||
<plurals name="ConversationListFragment_delete_selected_conversations">
|
||||
<item quantity="one">Delete selected conversation?</item>
|
||||
|
@ -2047,6 +2055,8 @@
|
|||
<string name="ConversationUpdateItem_invite_friends">Invite friends</string>
|
||||
<string name="ConversationUpdateItem_enable_call_notifications">Enable Call Notifications</string>
|
||||
<string name="ConversationUpdateItem_update_contact">Update contact</string>
|
||||
<!-- Update item button text to show to block a recipient from requesting to join via group link -->
|
||||
<string name="ConversationUpdateItem_block_request">Block request</string>
|
||||
<string name="ConversationUpdateItem_no_groups_in_common_review_requests_carefully">No groups in common. Review requests carefully.</string>
|
||||
<string name="ConversationUpdateItem_no_contacts_in_this_group_review_requests_carefully">No contacts in this group. Review requests carefully.</string>
|
||||
<string name="ConversationUpdateItem_view">View</string>
|
||||
|
|
|
@ -627,6 +627,9 @@ public final class DecryptedGroupUtil {
|
|||
changeIsEmptyExceptForProfileKeyChanges(change);
|
||||
}
|
||||
|
||||
/*
|
||||
* When updating this, update {@link #changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(DecryptedGroupChange)}
|
||||
*/
|
||||
public static boolean changeIsEmptyExceptForProfileKeyChanges(DecryptedGroupChange change) {
|
||||
return change.getNewMembersCount() == 0 && // field 3
|
||||
change.getDeleteMembersCount() == 0 && // field 4
|
||||
|
@ -650,6 +653,28 @@ public final class DecryptedGroupUtil {
|
|||
change.getDeleteBannedMembersCount() == 0; // field 23
|
||||
}
|
||||
|
||||
public static boolean changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(DecryptedGroupChange change) {
|
||||
return (change.getNewBannedMembersCount() != 0 || change.getDeleteBannedMembersCount() != 0) &&
|
||||
change.getNewMembersCount() == 0 && // field 3
|
||||
change.getDeleteMembersCount() == 0 && // field 4
|
||||
change.getModifyMemberRolesCount() == 0 && // field 5
|
||||
change.getNewPendingMembersCount() == 0 && // field 7
|
||||
change.getDeletePendingMembersCount() == 0 && // field 8
|
||||
change.getPromotePendingMembersCount() == 0 && // field 9
|
||||
!change.hasNewTitle() && // field 10
|
||||
!change.hasNewAvatar() && // field 11
|
||||
!change.hasNewTimer() && // field 12
|
||||
isEmpty(change.getNewAttributeAccess()) && // field 13
|
||||
isEmpty(change.getNewMemberAccess()) && // field 14
|
||||
isEmpty(change.getNewInviteLinkAccess()) && // field 15
|
||||
change.getNewRequestingMembersCount() == 0 && // field 16
|
||||
change.getDeleteRequestingMembersCount() == 0 && // field 17
|
||||
change.getPromoteRequestingMembersCount() == 0 && // field 18
|
||||
change.getNewInviteLinkPassword().size() == 0 && // field 19
|
||||
!change.hasNewDescription() && // field 20
|
||||
isEmpty(change.getNewIsAnnouncementGroup()); // field 21
|
||||
}
|
||||
|
||||
static boolean isEmpty(AccessControl.AccessRequired newAttributeAccess) {
|
||||
return newAttributeAccess == AccessControl.AccessRequired.UNKNOWN;
|
||||
}
|
||||
|
@ -657,4 +682,8 @@ public final class DecryptedGroupUtil {
|
|||
static boolean isEmpty(EnabledState enabledState) {
|
||||
return enabledState == EnabledState.UNKNOWN;
|
||||
}
|
||||
|
||||
public static boolean changeIsSilent(DecryptedGroupChange plainGroupChange) {
|
||||
return changeIsEmptyExceptForProfileKeyChanges(plainGroupChange) || changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(plainGroupChange);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue