Groups V2 invite decline.

master
Alan Evans 2020-07-15 15:40:13 -03:00 committed by Greyson Parrelli
parent 1ce36c1069
commit 644af87782
13 changed files with 245 additions and 87 deletions

View File

@ -2847,25 +2847,44 @@ public class ConversationActivity extends PassphraseRequiredActivity
@Override
public void onMessageRequest(@NonNull MessageRequestViewModel viewModel) {
messageRequestBottomView.setAcceptOnClickListener(v -> viewModel.onAccept(this::showGroupChangeErrorToast));
messageRequestBottomView.setAcceptOnClickListener(v -> viewModel.onAccept());
messageRequestBottomView.setDeleteOnClickListener(v -> onMessageRequestDeleteClicked(viewModel));
messageRequestBottomView.setBlockOnClickListener(v -> onMessageRequestBlockClicked(viewModel));
messageRequestBottomView.setUnblockOnClickListener(v -> onMessageRequestUnblockClicked(viewModel));
viewModel.getRecipient().observe(this, this::presentMessageRequestBottomViewTo);
viewModel.getMessageRequestDisplayState().observe(this, this::presentMessageRequestDisplayState);
viewModel.getFailures().observe(this, this::showGroupChangeErrorToast);
viewModel.getMessageRequestStatus().observe(this, status -> {
switch (status) {
case IDLE:
hideMessageRequestBusy();
break;
case ACCEPTING:
case BLOCKING:
case DELETING:
showMessageRequestBusy();
break;
case ACCEPTED:
hideMessageRequestBusy();
messageRequestBottomView.setVisibility(View.GONE);
return;
break;
case DELETED:
case BLOCKED:
hideMessageRequestBusy();
finish();
}
});
}
private void showMessageRequestBusy() {
messageRequestBottomView.showBusy();
}
private void hideMessageRequestBusy() {
messageRequestBottomView.hideBusy();
}
private void showGroupChangeErrorToast(@NonNull GroupChangeFailureReason e) {
Toast.makeText(this, GroupErrors.getUserDisplayMessage(e), Toast.LENGTH_LONG).show();
}

View File

@ -127,11 +127,15 @@ public final class GroupManager {
}
@WorkerThread
public static boolean silentLeaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId) {
public static void leaveGroupFromBlockOrMessageRequest(@NonNull Context context, @NonNull GroupId.Push groupId)
throws IOException, GroupChangeBusyException, GroupChangeFailedException
{
if (groupId.isV2()) {
throw new AssertionError("NYI"); // TODO [Alan] GV2 support silent leave for block and leave operations on GV2
leaveGroup(context, groupId.requireV2());
} else {
return GroupManagerV1.silentLeaveGroup(context, groupId.requireV1());
if (!GroupManagerV1.silentLeaveGroup(context, groupId.requireV1())) {
throw new GroupChangeFailedException();
}
}
}

View File

@ -14,6 +14,8 @@ import org.signal.storageservice.protos.groups.Member;
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.VerificationFailedException;
import org.signal.zkgroup.groups.GroupMasterKey;
import org.signal.zkgroup.groups.GroupSecretParams;
@ -54,6 +56,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@ -268,7 +271,20 @@ final class GroupManagerV2 {
@NonNull GroupManager.GroupActionResult leaveGroup()
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
return ejectMember(Recipient.self().getId());
Recipient self = Recipient.self();
GroupDatabase.GroupRecord groupRecord = groupDatabase.getGroup(groupId).get();
List<DecryptedPendingMember> pendingMembersList = groupRecord.requireV2GroupProperties().getDecryptedGroup().getPendingMembersList();
Optional<DecryptedPendingMember> selfPendingMember = DecryptedGroupUtil.findPendingByUuid(pendingMembersList, selfUuid);
if (selfPendingMember.isPresent()) {
try {
return cancelInvites(Collections.singleton(new UuidCiphertext(selfPendingMember.get().getUuidCipherText().toByteArray())));
} catch (InvalidInputException e) {
throw new AssertionError(e);
}
} else {
return ejectMember(self.getId());
}
}
@WorkerThread

View File

@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
@ -160,6 +161,17 @@ final class ManageGroupRepository {
});
}
void blockAndLeaveGroup(@NonNull GroupChangeErrorCallback error) {
SignalExecutors.UNBOUNDED.execute(() -> {
try {
RecipientUtil.block(context, Recipient.externalGroup(context, groupId));
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
}
});
}
static final class GroupStateResult {
private final long threadId;

View File

@ -25,6 +25,8 @@ import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.loaders.MediaLoader;
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.groups.GroupAccessControl;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.LiveGroup;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
@ -41,6 +43,7 @@ import org.thoughtcrime.securesms.util.SingleLiveEvent;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -205,8 +208,10 @@ public class ManageGroupViewModel extends ViewModel {
}
void blockAndLeave(@NonNull FragmentActivity activity) {
manageGroupRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient,
() -> RecipientUtil.block(context, recipient)));
manageGroupRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity,
activity.getLifecycle(),
recipient,
() -> manageGroupRepository.blockAndLeaveGroup(this::showErrorToast)));
}
void unblock(@NonNull FragmentActivity activity) {

View File

@ -103,6 +103,11 @@ public class SendReadReceiptJob extends BaseJob {
return;
}
if (recipient.isGroup()) {
Log.w(TAG, "Refusing to send receipts to group");
return;
}
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
SignalServiceAddress remoteAddress = RecipientUtil.toSignalServiceAddress(context, recipient);
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ, messageIds, timestamp);

View File

@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.util.guava.Optional;
@ -57,8 +56,8 @@ final class MessageRequestRepository {
void getMemberCount(@NonNull RecipientId recipientId, @NonNull Consumer<GroupMemberCount> onMemberCountLoaded) {
executor.execute(() -> {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
Optional<GroupDatabase.GroupRecord> groupRecord = groupDatabase.getGroup(recipientId);
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
Optional<GroupDatabase.GroupRecord> groupRecord = groupDatabase.getGroup(recipientId);
onMemberCountLoaded.accept(groupRecord.transform(record -> {
if (record.isV2Group()) {
DecryptedGroup decryptedGroup = record.requireV2GroupProperties().getDecryptedGroup();
@ -90,9 +89,8 @@ final class MessageRequestRepository {
void acceptMessageRequest(@NonNull LiveRecipient liveRecipient,
long threadId,
@NonNull Runnable onMessageRequestAccepted,
@NonNull GroupChangeErrorCallback mainThreadError)
@NonNull GroupChangeErrorCallback error)
{
GroupChangeErrorCallback error = e -> Util.runOnMain(() -> mainThreadError.onError(e));
executor.execute(()-> {
if (liveRecipient.get().isPushV2Group()) {
try {
@ -130,27 +128,47 @@ final class MessageRequestRepository {
});
}
void deleteMessageRequest(@NonNull LiveRecipient recipient, long threadId, @NonNull Runnable onMessageRequestDeleted) {
void deleteMessageRequest(@NonNull LiveRecipient recipient,
long threadId,
@NonNull Runnable onMessageRequestDeleted,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(() -> {
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
threadDatabase.deleteConversation(threadId);
Recipient resolved = recipient.resolve();
if (recipient.resolve().isGroup()) {
RecipientUtil.leaveGroup(context, recipient.get());
if (resolved.isGroup() && resolved.requireGroupId().isPush()) {
try {
GroupManager.leaveGroupFromBlockOrMessageRequest(context, resolved.requireGroupId().requirePush());
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
return;
}
}
if (TextSecurePreferences.isMultiDevice(context)) {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forDelete(recipient.getId()));
}
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
threadDatabase.deleteConversation(threadId);
onMessageRequestDeleted.run();
});
}
void blockMessageRequest(@NonNull LiveRecipient liveRecipient, @NonNull Runnable onMessageRequestBlocked) {
void blockMessageRequest(@NonNull LiveRecipient liveRecipient,
@NonNull Runnable onMessageRequestBlocked,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(() -> {
Recipient recipient = liveRecipient.resolve();
RecipientUtil.block(context, recipient);
try {
RecipientUtil.block(context, recipient);
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
error.onError(GroupChangeFailureReason.OTHER);
return;
}
liveRecipient.refresh();
if (TextSecurePreferences.isMultiDevice(context)) {
@ -161,10 +179,19 @@ final class MessageRequestRepository {
});
}
void blockAndDeleteMessageRequest(@NonNull LiveRecipient liveRecipient, long threadId, @NonNull Runnable onMessageRequestBlocked) {
void blockAndDeleteMessageRequest(@NonNull LiveRecipient liveRecipient,
long threadId,
@NonNull Runnable onMessageRequestBlocked,
@NonNull GroupChangeErrorCallback error)
{
executor.execute(() -> {
Recipient recipient = liveRecipient.resolve();
RecipientUtil.block(context, recipient);
try{
RecipientUtil.block(context, recipient);
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
error.onError(GroupChangeFailureReason.OTHER);
return;
}
liveRecipient.refresh();
DatabaseFactory.getThreadDatabase(context).deleteConversation(threadId);

View File

@ -11,12 +11,11 @@ import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.livedata.LiveDataTriple;
@ -26,13 +25,14 @@ import java.util.List;
public class MessageRequestViewModel extends ViewModel {
private final SingleLiveEvent<Status> status = new SingleLiveEvent<>();
private final MutableLiveData<Recipient> recipient = new MutableLiveData<>();
private final MutableLiveData<List<String>> groups = new MutableLiveData<>(Collections.emptyList());
private final MutableLiveData<GroupMemberCount> memberCount = new MutableLiveData<>(GroupMemberCount.ZERO);
private final MutableLiveData<DisplayState> displayState = new MutableLiveData<>();
private final LiveData<RecipientInfo> recipientInfo = Transformations.map(new LiveDataTriple<>(recipient, memberCount, groups),
triple -> new RecipientInfo(triple.first(), triple.second(), triple.third()));
private final SingleLiveEvent<Status> status = new SingleLiveEvent<>();
private final SingleLiveEvent<GroupChangeFailureReason> failures = new SingleLiveEvent<>();
private final MutableLiveData<Recipient> recipient = new MutableLiveData<>();
private final MutableLiveData<List<String>> groups = new MutableLiveData<>(Collections.emptyList());
private final MutableLiveData<GroupMemberCount> memberCount = new MutableLiveData<>(GroupMemberCount.ZERO);
private final MutableLiveData<DisplayState> displayState = new MutableLiveData<>();
private final LiveData<RecipientInfo> recipientInfo = Transformations.map(new LiveDataTriple<>(recipient, memberCount, groups),
triple -> new RecipientInfo(triple.first(), triple.second(), triple.third()));
private final MessageRequestRepository repository;
@ -85,44 +85,58 @@ public class MessageRequestViewModel extends ViewModel {
return status;
}
public LiveData<GroupChangeFailureReason> getFailures() {
return failures;
}
public boolean shouldShowMessageRequest() {
return displayState.getValue() == DisplayState.DISPLAY_MESSAGE_REQUEST;
}
@MainThread
public void onAccept(@NonNull GroupChangeErrorCallback error) {
repository.acceptMessageRequest(liveRecipient, threadId, () -> {
status.postValue(Status.ACCEPTED);
},
error);
public void onAccept() {
status.setValue(Status.ACCEPTING);
repository.acceptMessageRequest(liveRecipient,
threadId,
() -> status.postValue(Status.ACCEPTED),
this::onGroupChangeError);
}
@MainThread
public void onDelete() {
repository.deleteMessageRequest(liveRecipient, threadId, () -> {
status.postValue(Status.DELETED);
});
status.setValue(Status.DELETING);
repository.deleteMessageRequest(liveRecipient,
threadId,
() -> status.postValue(Status.DELETED),
this::onGroupChangeError);
}
@MainThread
public void onBlock() {
repository.blockMessageRequest(liveRecipient, () -> {
status.postValue(Status.BLOCKED);
});
status.setValue(Status.BLOCKING);
repository.blockMessageRequest(liveRecipient,
() -> status.postValue(Status.BLOCKED),
this::onGroupChangeError);
}
@MainThread
public void onUnblock() {
repository.unblockAndAccept(liveRecipient, threadId, () -> {
status.postValue(Status.ACCEPTED);
});
repository.unblockAndAccept(liveRecipient,
threadId,
() -> status.postValue(Status.ACCEPTED));
}
@MainThread
public void onBlockAndDelete() {
repository.blockAndDeleteMessageRequest(liveRecipient, threadId, () -> {
status.postValue(Status.BLOCKED);
});
repository.blockAndDeleteMessageRequest(liveRecipient,
threadId,
() -> status.postValue(Status.BLOCKED),
this::onGroupChangeError);
}
private void onGroupChangeError(@NonNull GroupChangeFailureReason error) {
status.postValue(Status.IDLE);
failures.postValue(error);
}
private void loadRecipient() {
@ -191,8 +205,12 @@ public class MessageRequestViewModel extends ViewModel {
}
public enum Status {
IDLE,
BLOCKING,
BLOCKED,
DELETING,
DELETED,
ACCEPTING,
ACCEPTED
}

View File

@ -12,19 +12,24 @@ import androidx.core.text.HtmlCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Debouncer;
import org.thoughtcrime.securesms.util.HtmlUtil;
public class MessageRequestsBottomView extends ConstraintLayout {
private final Debouncer showProgressDebouncer = new Debouncer(250);
private TextView question;
private View accept;
private View block;
private View delete;
private View bigDelete;
private View bigUnblock;
private View busyIndicator;
private Group normalButtons;
private Group blockedButtons;
private Group activeGroup;
public MessageRequestsBottomView(Context context) {
super(context);
@ -52,6 +57,7 @@ public class MessageRequestsBottomView extends ConstraintLayout {
bigUnblock = findViewById(R.id.message_request_big_unblock);
normalButtons = findViewById(R.id.message_request_normal_buttons);
blockedButtons = findViewById(R.id.message_request_blocked_buttons);
busyIndicator = findViewById(R.id.message_request_busy_indicator);
}
public void setRecipient(@NonNull Recipient recipient) {
@ -62,8 +68,7 @@ public class MessageRequestsBottomView extends ConstraintLayout {
String name = recipient.getProfileName().isEmpty() ? recipient.getDisplayName(getContext()) : recipient.getProfileName().getGivenName();
question.setText(HtmlCompat.fromHtml(getContext().getString(R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_wont_receive_any_messages_until_you_unblock_them, HtmlUtil.bold(name)), 0));
}
normalButtons.setVisibility(GONE);
blockedButtons.setVisibility(VISIBLE);
setActiveInactiveGroups(blockedButtons, normalButtons);
} else {
if (recipient.isGroup()) {
if (recipient.isPushV2Group()) {
@ -75,8 +80,31 @@ public class MessageRequestsBottomView extends ConstraintLayout {
String name = recipient.getProfileName().isEmpty() ? recipient.getDisplayName(getContext()) : recipient.getProfileName().getGivenName();
question.setText(HtmlCompat.fromHtml(getContext().getString(R.string.MessageRequestBottomView_do_you_want_to_let_s_message_you_they_wont_know_youve_seen_their_messages_until_you_accept, HtmlUtil.bold(name)), 0));
}
normalButtons.setVisibility(VISIBLE);
blockedButtons.setVisibility(GONE);
setActiveInactiveGroups(normalButtons, blockedButtons);
}
}
private void setActiveInactiveGroups(@NonNull Group activeGroup, @NonNull Group inActiveGroup) {
int initialVisibility = this.activeGroup != null ? this.activeGroup.getVisibility() : VISIBLE;
this.activeGroup = activeGroup;
inActiveGroup.setVisibility(GONE);
activeGroup.setVisibility(initialVisibility);
}
public void showBusy() {
showProgressDebouncer.publish(() -> busyIndicator.setVisibility(VISIBLE));
if (activeGroup != null) {
activeGroup.setVisibility(INVISIBLE);
}
}
public void hideBusy() {
showProgressDebouncer.clear();
busyIndicator.setVisibility(GONE);
if (activeGroup != null) {
activeGroup.setVisibility(VISIBLE);
}
}

View File

@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.recipients;
import android.content.Context;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -9,12 +8,13 @@ import androidx.annotation.WorkerThread;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
@ -66,8 +66,32 @@ public class RecipientUtil {
return resolved.isPushGroup() || resolved.hasServiceIdentifier();
}
/**
* You can call this for non-groups and not have to handle any network errors.
*/
@WorkerThread
public static void block(@NonNull Context context, @NonNull Recipient recipient) {
public static void blockNonGroup(@NonNull Context context, @NonNull Recipient recipient) {
if (recipient.isGroup()) {
throw new AssertionError();
}
try {
block(context, recipient);
} catch (GroupChangeBusyException | IOException | GroupChangeFailedException e) {
throw new AssertionError(e);
}
}
/**
* You can call this for any type of recipient but must handle network errors that can occur from
* GV2.
* <p>
* GV2 operations can also take longer due to the network.
*/
@WorkerThread
public static void block(@NonNull Context context, @NonNull Recipient recipient)
throws GroupChangeBusyException, IOException, GroupChangeFailedException
{
if (!isBlockable(recipient)) {
throw new AssertionError("Recipient is not blockable!");
}
@ -76,8 +100,8 @@ public class RecipientUtil {
DatabaseFactory.getRecipientDatabase(context).setBlocked(resolved.getId(), true);
if (resolved.isGroup()) {
leaveGroup(context, recipient);
if (resolved.isGroup() && recipient.getGroupId().get().isPush()) {
GroupManager.leaveGroupFromBlockOrMessageRequest(context, recipient.getGroupId().get().requirePush());
}
if (resolved.isSystemContact() || resolved.isProfileSharing() || isProfileSharedViaGroup(context,resolved)) {
@ -101,20 +125,6 @@ public class RecipientUtil {
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forAccept(recipient.getId()));
}
@WorkerThread
public static void leaveGroup(@NonNull Context context, @NonNull Recipient recipient) {
Recipient resolved = recipient.resolve();
if (!resolved.isGroup()) {
throw new AssertionError("Not a group!");
}
if (!GroupManager.silentLeaveGroup(context, resolved.requireGroupId().requirePush())) {
Log.w(TAG, "Failed to leave group.");
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
}
}
/**
* If true, the new message request UI does not need to be shown, and it's safe to send read
* receipts.

View File

@ -120,7 +120,7 @@ final class RecipientDialogViewModel extends ViewModel {
}
void onBlockClicked(@NonNull FragmentActivity activity) {
recipientDialogRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.block(context, recipient)));
recipientDialogRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.blockNonGroup(context, recipient)));
}
void onUnblockClicked(@NonNull FragmentActivity activity) {

View File

@ -210,7 +210,7 @@ public final class ManageRecipientViewModel extends ViewModel {
}
void onBlockClicked(@NonNull FragmentActivity activity) {
withRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.block(context, recipient)));
withRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.blockNonGroup(context, recipient)));
}
void onUnblockClicked(@NonNull FragmentActivity activity) {

View File

@ -11,8 +11,8 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="11dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Description"
android:paddingTop="16dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Description"
app:layout_constraintBottom_toTopOf="@id/message_request_button_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -20,12 +20,12 @@
<Button
android:id="@+id/message_request_block"
style="@style/Signal.MessageRequest.Button.Deny"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
style="@style/Signal.MessageRequest.Button.Deny"
android:text="@string/MessageRequestBottomView_block"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/message_request_delete"
@ -34,10 +34,10 @@
<Button
android:id="@+id/message_request_delete"
style="@style/Signal.MessageRequest.Button.Deny"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
style="@style/Signal.MessageRequest.Button.Deny"
android:text="@string/MessageRequestBottomView_delete"
app:layout_constraintBottom_toBottomOf="@id/message_request_block"
app:layout_constraintEnd_toStartOf="@+id/message_request_accept"
@ -47,10 +47,10 @@
<Button
android:id="@+id/message_request_accept"
style="@style/Signal.MessageRequest.Button.Accept"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="16dp"
style="@style/Signal.MessageRequest.Button.Accept"
android:text="@string/MessageRequestBottomView_accept"
app:layout_constraintBottom_toBottomOf="@id/message_request_block"
app:layout_constraintEnd_toEndOf="parent"
@ -60,35 +60,35 @@
<Button
android:id="@+id/message_request_big_delete"
style="@style/Signal.MessageRequest.Button.Deny"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
style="@style/Signal.MessageRequest.Button.Deny"
android:text="@string/MessageRequestBottomView_delete"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/message_request_big_unblock"/>
app:layout_constraintEnd_toStartOf="@id/message_request_big_unblock"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/message_request_big_unblock"
style="@style/Signal.MessageRequest.Button.Accept"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="16dp"
style="@style/Signal.MessageRequest.Button.Accept"
android:text="@string/MessageRequestBottomView_unblock"
app:layout_constraintTop_toTopOf="@id/message_request_big_delete"
app:layout_constraintStart_toEndOf="@id/message_request_big_delete"
app:layout_constraintBottom_toBottomOf="@id/message_request_big_delete"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@id/message_request_big_delete"/>
app:layout_constraintStart_toEndOf="@id/message_request_big_delete"
app:layout_constraintTop_toTopOf="@id/message_request_big_delete" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/message_request_button_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="top"
app:constraint_referenced_ids="message_request_block,message_request_big_delete"/>
app:constraint_referenced_ids="message_request_block,message_request_big_delete" />
<androidx.constraintlayout.widget.Group
android:id="@+id/message_request_normal_buttons"
@ -102,6 +102,20 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
tools:visibility="visible"
app:constraint_referenced_ids="message_request_big_delete,message_request_big_unblock" />
app:constraint_referenced_ids="message_request_big_delete,message_request_big_unblock"
tools:visibility="visible" />
<ProgressBar
android:id="@+id/message_request_busy_indicator"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/message_request_question"
tools:visibility="visible" />
</merge>