Fix block/unblock causing ANR in recipient bottom sheet.

This commit is contained in:
Cody Henthorne
2026-05-27 13:00:57 -04:00
committed by Michelle Tang
parent 7b23110cac
commit abcd65603c
8 changed files with 61 additions and 38 deletions
@@ -23,45 +23,25 @@ public final class BlockUnblockDialog {
private BlockUnblockDialog() {}
public static void showReportSpamFor(@NonNull Context context,
@NonNull Lifecycle lifecycle,
@NonNull Recipient recipient,
@NonNull Runnable onReportSpam,
@Nullable Runnable onBlockAndReportSpam)
{
SimpleTask.run(lifecycle,
() -> buildReportSpamFor(context, recipient, onReportSpam, onBlockAndReportSpam),
AlertDialog.Builder::show);
buildReportSpamFor(context, recipient, onReportSpam, onBlockAndReportSpam).show();
}
public static void showBlockFor(@NonNull Context context,
@NonNull Lifecycle lifecycle,
@NonNull Recipient recipient,
@NonNull Runnable onBlock)
{
SimpleTask.run(lifecycle,
() -> buildBlockFor(context, recipient, onBlock, null),
AlertDialog.Builder::show);
}
public static void showBlockAndReportSpamFor(@NonNull Context context,
@NonNull Lifecycle lifecycle,
@NonNull Recipient recipient,
@NonNull Runnable onBlock,
@NonNull Runnable onBlockAndReportSpam)
{
SimpleTask.run(lifecycle,
() -> buildBlockFor(context, recipient, onBlock, onBlockAndReportSpam),
AlertDialog.Builder::show);
buildBlockFor(context, recipient, onBlock, null).show();
}
public static void showUnblockFor(@NonNull Context context,
@NonNull Lifecycle lifecycle,
@NonNull Recipient recipient,
@NonNull Runnable onUnblock)
{
SimpleTask.run(lifecycle,
() -> buildUnblockFor(context, recipient, onUnblock),
AlertDialog.Builder::show);
buildUnblockFor(context, recipient, onUnblock).show();
}
@WorkerThread
@@ -78,7 +78,7 @@ public class BlockedUsersFragment extends Fragment {
}
private void handleRecipientClicked(@NonNull Recipient recipient) {
BlockUnblockDialog.showUnblockFor(requireContext(), getViewLifecycleOwner().getLifecycle(), recipient, () -> {
BlockUnblockDialog.showUnblockFor(requireContext(), recipient, () -> {
viewModel.unblock(recipient.getId());
});
}
@@ -12,8 +12,11 @@ import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.CircularProgressIndicator
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.padding
import org.thoughtcrime.securesms.util.visible
/**
* Wraps a normal progress dialog for showing blocking in-progress UI.
@@ -81,9 +84,15 @@ class SignalProgressDialog private constructor(
val progressView: CircularProgressIndicator = customView.findViewById(R.id.progress_dialog_progressbar)
titleView.text = title
titleView.visible = title != null
messageView.text = message
messageView.visible = message != null
progressView.isIndeterminate = indeterminate
if (title == null && message == null) {
progressView.padding(top = 32.dp, bottom = 32.dp)
}
builder.setView(customView)
val dialog = builder.show()
@@ -1041,11 +1041,11 @@ class ConversationSettingsFragment :
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
if (state.recipient.isBlocked) {
BlockUnblockDialog.showUnblockFor(requireContext(), viewLifecycleOwner.lifecycle, state.recipient) {
BlockUnblockDialog.showUnblockFor(requireContext(), state.recipient) {
viewModel.unblock()
}
} else {
BlockUnblockDialog.showBlockFor(requireContext(), viewLifecycleOwner.lifecycle, state.recipient) {
BlockUnblockDialog.showBlockFor(requireContext(), state.recipient) {
viewModel.block()
}
}
@@ -1061,7 +1061,6 @@ class ConversationSettingsFragment :
onClick = {
BlockUnblockDialog.showReportSpamFor(
requireContext(),
viewLifecycleOwner.lifecycle,
state.recipient,
{
viewModel
@@ -1110,7 +1109,6 @@ class ConversationSettingsFragment :
onClick = {
BlockUnblockDialog.showReportSpamFor(
requireContext(),
viewLifecycleOwner.lifecycle,
state.recipient,
{
viewModel
@@ -394,7 +394,7 @@ private fun UserMessagesHost(
is UserMessage.Prompt.ConfirmBlockRecipient -> {
val lifecycle = LocalLifecycleOwner.current.lifecycle
LaunchedEffect(userMessage.recipient) {
BlockUnblockDialog.showBlockFor(context, lifecycle, userMessage.recipient) {
BlockUnblockDialog.showBlockFor(context, userMessage.recipient) {
onBlockConfirmed(userMessage.recipient)
}
}
@@ -2880,7 +2880,6 @@ class ConversationFragment :
BlockUnblockDialog.showReportSpamFor(
requireContext(),
lifecycle,
recipient,
{
messageRequestViewModel
@@ -2928,7 +2927,6 @@ class ConversationFragment :
BlockUnblockDialog.showBlockFor(
requireContext(),
lifecycle,
recipient
) {
messageRequestViewModel
@@ -2947,7 +2945,6 @@ class ConversationFragment :
BlockUnblockDialog.showUnblockFor(
requireContext(),
lifecycle,
recipient
) {
messageRequestViewModel
@@ -20,17 +20,21 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.signal.core.ui.BottomSheetUtil
import org.signal.core.ui.FixedRoundedCornerBottomSheetDialogFragment
import org.signal.core.util.logging.Log
import org.signal.core.util.requireDrawable
import org.thoughtcrime.securesms.BlockUnblockDialog
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.avatar.view.AvatarView
import org.thoughtcrime.securesms.badges.BadgeImageView
import org.thoughtcrime.securesms.badges.view.ViewBadgeBottomSheetDialogFragment
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
import org.thoughtcrime.securesms.components.SignalProgressDialog
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
import org.thoughtcrime.securesms.conversation.v2.data.AvatarDownloadStateCache
@@ -341,8 +345,19 @@ class RecipientBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDialogFr
ViewBadgeBottomSheetDialogFragment.show(getParentFragmentManager(), recipientId, null)
}
blockButton.setOnClickListener { viewModel.onBlockClicked(requireActivity()) }
unblockButton.setOnClickListener { viewModel.onUnblockClicked(requireActivity()) }
blockButton.setOnClickListener {
val recipient = viewModel.recipient.value ?: return@setOnClickListener
BlockUnblockDialog.showBlockFor(requireContext(), recipient) {
runWithProgress { viewModel.onBlockClicked(recipient) }
}
}
unblockButton.setOnClickListener {
val recipient = viewModel.recipient.value ?: return@setOnClickListener
BlockUnblockDialog.showUnblockFor(requireContext(), recipient) {
runWithProgress { viewModel.onUnblockClicked(recipient) }
}
}
makeGroupAdminButton.setOnClickListener { viewModel.onMakeGroupAdminClicked(requireActivity()) }
removeAdminButton.setOnClickListener { viewModel.onRemoveGroupAdminClicked(requireActivity()) }
@@ -451,6 +466,30 @@ class RecipientBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDialogFr
}
}
private fun runWithProgress(operation: () -> Unit) {
lifecycleScope.launch(Dispatchers.Main) {
val task = async(Dispatchers.Default) {
operation()
}
delay(250)
if (task.isActive) {
val dialog = SignalProgressDialog.show(
requireContext(),
indeterminate = true,
cancelable = false
)
try {
task.await()
} finally {
dialog.dismiss()
}
}
}
}
interface Callback {
fun onRecipientBottomSheetDismissed()
fun onMessageClicked()
@@ -221,12 +221,12 @@ final class RecipientDialogViewModel extends ViewModel {
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startVideoCall(activity, recipient, onUserAlreadyInAnotherCall));
}
void onBlockClicked(@NonNull FragmentActivity activity) {
recipientDialogRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.blockNonGroup(context, recipient)));
void onBlockClicked(@NonNull Recipient recipient) {
RecipientUtil.blockNonGroup(context, recipient);
}
void onUnblockClicked(@NonNull FragmentActivity activity) {
recipientDialogRepository.getRecipient(recipient -> BlockUnblockDialog.showUnblockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.unblock(recipient)));
void onUnblockClicked(@NonNull Recipient recipient) {
RecipientUtil.unblock(recipient);
}
void onViewSafetyNumberClicked(@NonNull Activity activity, @NonNull IdentityRecord identityRecord) {