From 43e3ef2bee6edbe482e1e603a13ff5a7c266db0a Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 23 Nov 2020 13:10:35 -0500 Subject: [PATCH] Refactor Message Request logic to fix some GV1->GV2 bugs. --- .../conversation/ConversationActivity.java | 54 ++++---- .../ConversationGroupViewModel.java | 16 ++- .../securesms/database/GroupDatabase.java | 5 +- .../groups/GroupsV1MigrationUtil.java | 8 ++ .../MessageRequestRepository.java | 108 +++++++++------- .../messagerequests/MessageRequestState.java | 39 ++++++ .../MessageRequestViewModel.java | 122 ++---------------- .../MessageRequestsBottomView.java | 3 +- .../ManageRecipientFragment.java | 13 +- .../res/layout/recipient_manage_fragment.xml | 34 +++-- app/src/main/res/values/strings.xml | 7 +- 11 files changed, 204 insertions(+), 205 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestState.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 47333095f..b596753ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -190,6 +190,7 @@ import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult; import org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity; +import org.thoughtcrime.securesms.messagerequests.MessageRequestState; import org.thoughtcrime.securesms.messagerequests.MessageRequestViewModel; import org.thoughtcrime.securesms.messagerequests.MessageRequestsBottomView; import org.thoughtcrime.securesms.mms.AttachmentManager; @@ -3140,8 +3141,7 @@ public class ConversationActivity extends PassphraseRequiredActivity messageRequestBottomView.setGroupV1MigrationContinueListener(v -> GroupsV1MigrationInitiationBottomSheetDialogFragment.showForInitiation(getSupportFragmentManager(), recipient.getId())); viewModel.getRequestReviewDisplayState().observe(this, this::presentRequestReviewBanner); - viewModel.getMessageData().observe(this, this::presentMessageRequestBottomViewTo); - viewModel.getMessageRequestDisplayState().observe(this, this::presentMessageRequestDisplayState); + viewModel.getMessageData().observe(this, this::presentMessageRequestState); viewModel.getFailures().observe(this, this::showGroupChangeErrorToast); viewModel.getMessageRequestStatus().observe(this, status -> { switch (status) { @@ -3155,7 +3155,6 @@ public class ConversationActivity extends PassphraseRequiredActivity break; case ACCEPTED: hideMessageRequestBusy(); - messageRequestBottomView.setVisibility(View.GONE); break; case DELETED: case BLOCKED: @@ -3426,31 +3425,6 @@ public class ConversationActivity extends PassphraseRequiredActivity BlockUnblockDialog.showUnblockFor(this, getLifecycle(), recipient, requestModel::onUnblock); } - private void presentMessageRequestDisplayState(@NonNull MessageRequestViewModel.DisplayState displayState) { - if ((getIntent().hasExtra(TEXT_EXTRA) && !Util.isEmpty(getIntent().getStringExtra(TEXT_EXTRA))) || - getIntent().hasExtra(MEDIA_EXTRA) || - getIntent().hasExtra(STICKER_EXTRA)) - { - Log.d(TAG, "[presentMessageRequestDisplayState] Have extra, so ignoring provided state."); - messageRequestBottomView.setVisibility(View.GONE); - } else if (isPushGroupV1Conversation() && !isActiveGroup()) { - Log.d(TAG, "[presentMessageRequestDisplayState] Inactive push group V1, so ignoring provided state."); - messageRequestBottomView.setVisibility(View.GONE); - } else { - Log.d(TAG, "[presentMessageRequestDisplayState] " + displayState); - switch (displayState) { - case DISPLAY_MESSAGE_REQUEST: - messageRequestBottomView.setVisibility(View.VISIBLE); - break; - case DISPLAY_NONE: - messageRequestBottomView.setVisibility(View.GONE); - break; - } - } - - invalidateOptionsMenu(); - } - private static void hideMenuItem(@NonNull Menu menu, @IdRes int menuItem) { if (menu.findItem(menuItem) != null) { menu.findItem(menuItem).setVisible(false); @@ -3597,10 +3571,28 @@ public class ConversationActivity extends PassphraseRequiredActivity } } - private void presentMessageRequestBottomViewTo(@Nullable MessageRequestViewModel.MessageData messageData) { - if (messageData == null) return; + private void presentMessageRequestState(@Nullable MessageRequestViewModel.MessageData messageData) { + if ((getIntent().hasExtra(TEXT_EXTRA) && !Util.isEmpty(getIntent().getStringExtra(TEXT_EXTRA))) || + getIntent().hasExtra(MEDIA_EXTRA) || + getIntent().hasExtra(STICKER_EXTRA)) + { + Log.d(TAG, "[presentMessageRequestState] Have extra, so ignoring provided state."); + messageRequestBottomView.setVisibility(View.GONE); + } else if (isPushGroupV1Conversation() && !isActiveGroup()) { + Log.d(TAG, "[presentMessageRequestState] Inactive push group V1, so ignoring provided state."); + messageRequestBottomView.setVisibility(View.GONE); + } else if (messageData == null) { + Log.d(TAG, "[presentMessageRequestState] Null messageData. Ignoring."); + } else if (messageData.getMessageState() == MessageRequestState.NONE) { + Log.d(TAG, "[presentMessageRequestState] No message request necessary."); + messageRequestBottomView.setVisibility(View.GONE); + } else { + Log.d(TAG, "[presentMessageRequestState] " + messageData.getMessageState()); + messageRequestBottomView.setMessageData(messageData); + messageRequestBottomView.setVisibility(View.VISIBLE); + } - messageRequestBottomView.setMessageData(messageData); + invalidateOptionsMenu(); } private static class KeyboardImageDetails { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationGroupViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationGroupViewModel.java index 7ed8b34d3..360e2c771 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationGroupViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationGroupViewModel.java @@ -170,6 +170,14 @@ final class ConversationGroupViewModel extends ViewModel { return Collections.emptyList(); } + if (!record.isV2Group()) { + return Collections.emptyList(); + } + + if (!record.isActive() || record.isPendingMember(Recipient.self())) { + return Collections.emptyList(); + } + Set difference = SetUtil.difference(record.getFormerV1Members(), record.getMembers()); return Stream.of(Recipient.resolvedList(difference)) @@ -180,7 +188,13 @@ final class ConversationGroupViewModel extends ViewModel { @WorkerThread private static boolean mapToGroupV1MigrationReminder(@Nullable GroupRecord record) { - if (record == null || !record.isV1Group() || !record.isActive() || !FeatureFlags.groupsV1ManualMigration()) { + if (record == null || + !record.isV1Group() || + !record.isActive() || + !FeatureFlags.groupsV1ManualMigration() || + FeatureFlags.groupsV1ForcedMigration() || + !Recipient.resolved(record.getRecipientId()).isProfileSharing()) + { return false; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java index 4be2f5e6b..38bd05924 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -966,7 +966,10 @@ public final class GroupDatabase extends Database { } } - boolean isPendingMember(@NonNull Recipient recipient) { + /** + * Whether or not the recipient is a pending member. + */ + public boolean isPendingMember(@NonNull Recipient recipient) { if (isV2Group()) { Optional uuid = recipient.getUuid(); if (uuid.isPresent()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java index 5a0d3c322..00174a484 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupsV1MigrationUtil.java @@ -140,17 +140,25 @@ public final class GroupsV1MigrationUtil { DecryptedGroup decryptedGroup = performLocalMigration(context, gv1Id, threadId, groupRecipient); if (newlyCreated && decryptedGroup != null && !SignalStore.internalValues().disableGv1AutoMigrateNotification()) { + Log.i(TAG, "Sending no-op update to notify others."); GroupManager.sendNoopUpdate(context, gv2MasterKey, decryptedGroup); } } public static void performLocalMigration(@NonNull Context context, @NonNull GroupId.V1 gv1Id) throws IOException { + Log.i(TAG, "Beginning local migration!", new Throwable()); try (Closeable ignored = GroupsV2ProcessingLock.acquireGroupProcessingLock()) { + if (DatabaseFactory.getGroupDatabase(context).groupExists(gv1Id.deriveV2MigrationGroupId())) { + Log.w(TAG, "Group was already migrated! Could have been waiting for the lock.", new Throwable()); + return; + } + Recipient recipient = Recipient.externalGroupExact(context, gv1Id); long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient); performLocalMigration(context, gv1Id, threadId, recipient); + Log.i(TAG, "Migration complete!", new Throwable()); } catch (GroupChangeBusyException e) { throw new IOException(e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java index 75fd9d9b4..a469147a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestRepository.java @@ -72,44 +72,57 @@ final class MessageRequestRepository { }); } - void getMessageRequestState(@NonNull Recipient recipient, long threadId, @NonNull Consumer state) { - executor.execute(() -> state.accept(findMessageRequestState(recipient, threadId))); - } - @WorkerThread - private MessageRequestState findMessageRequestState(@NonNull Recipient recipient, long threadId) { - if (recipient.isGroup() && recipient.isPushV2Group()) { - 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.PENDING_MEMBER) { - return MessageRequestState.REQUIRED; - } - } - - if (recipient.isPushV1Group() && FeatureFlags.groupsV1ForcedMigration()) { - return MessageRequestState.REQUIRED; - } - - if (!RecipientUtil.isMessageRequestAccepted(context, threadId)) { + @NonNull MessageRequestState getMessageRequestState(@NonNull Recipient recipient, long threadId) { + if (recipient.isBlocked()) { 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.BLOCKED_GROUP; + } else { + return MessageRequestState.BLOCKED_INDIVIDUAL; + } + } else if (threadId <= 0) { + return MessageRequestState.NONE; + } else if (recipient.isPushV2Group()) { + switch (getGroupMemberLevel(recipient.getId())) { + case NOT_A_MEMBER: + return MessageRequestState.NONE; + case PENDING_MEMBER: + return MessageRequestState.GROUP_V2_INVITE; + default: + if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { + return MessageRequestState.NONE; + } else { + return MessageRequestState.GROUP_V2_ADD; + } + } + } else if (!RecipientUtil.isLegacyProfileSharingAccepted(recipient) && isLegacyThread(recipient)) { + if (recipient.isGroup()) { + return MessageRequestState.LEGACY_GROUP_V1; + } else { + return MessageRequestState.LEGACY_INDIVIDUAL; + } + } else if (recipient.isPushV1Group()) { + if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { + if (FeatureFlags.groupsV1ForcedMigration()) { + if (recipient.getParticipants().size() > FeatureFlags.groupLimits().getHardLimit()) { + return MessageRequestState.DEPRECATED_GROUP_V1_TOO_LARGE; + } else { + return MessageRequestState.DEPRECATED_GROUP_V1; + } + } else { + return MessageRequestState.NONE; + } + } else if (!recipient.isActiveGroup()) { + return MessageRequestState.NONE; + } else { + return MessageRequestState.GROUP_V1; } - - return MessageRequestState.REQUIRED; - } else if (!RecipientUtil.isLegacyProfileSharingAccepted(recipient) && threadId > 0) { - return MessageRequestState.REQUIRED; } else { - return MessageRequestState.NOT_REQUIRED; + if (RecipientUtil.isMessageRequestAccepted(context, threadId)) { + return MessageRequestState.NONE; + } else { + return MessageRequestState.INDIVIDUAL; + } } } @@ -259,23 +272,20 @@ final class MessageRequestRepository { }); } - @WorkerThread - boolean isPendingMember(@NonNull GroupId.V2 groupId) { - return DatabaseFactory.getGroupDatabase(context).isPendingMember(groupId, Recipient.self()); + private GroupDatabase.MemberLevel getGroupMemberLevel(@NonNull RecipientId recipientId) { + return DatabaseFactory.getGroupDatabase(context) + .getGroup(recipientId) + .transform(g -> g.memberLevel(Recipient.self())) + .or(GroupDatabase.MemberLevel.NOT_A_MEMBER); } - enum MessageRequestState { - /** - * Message request permission does not need to be gained at this time. - *

- * 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 + @WorkerThread + private boolean isLegacyThread(@NonNull Recipient recipient) { + Context context = ApplicationDependencies.getApplication(); + Long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient.getId()); + + return threadId != null && + (RecipientUtil.hasSentMessageInThread(context, threadId) || RecipientUtil.isPreMessageRequestThread(context, threadId)); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestState.java b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestState.java new file mode 100644 index 000000000..d0d8e85b7 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestState.java @@ -0,0 +1,39 @@ +package org.thoughtcrime.securesms.messagerequests; + +/** + * An enum representing the possible message request states a user can be in. + */ +public enum MessageRequestState { + /** No message request necessary */ + NONE, + + /** A user is blocked */ + BLOCKED_INDIVIDUAL, + + /** A group is blocked */ + BLOCKED_GROUP, + + /** An individual conversation that existed pre-message-requests but doesn't have profile sharing enabled */ + LEGACY_INDIVIDUAL, + + /** A V1 group conversation that existed pre-message-requests but doesn't have profile sharing enabled */ + LEGACY_GROUP_V1, + + /** A V1 group conversation that is no longer allowed, because we've forced GV2 on. */ + DEPRECATED_GROUP_V1, + + /** A V1 group conversation that is no longer allowed, because we've forced GV2 on, but it's also too large to migrate. Nothing we can do. */ + DEPRECATED_GROUP_V1_TOO_LARGE, + + /** A message request is needed for a V1 group */ + GROUP_V1, + + /** An invite response is needed for a V2 group */ + GROUP_V2_INVITE, + + /** A message request is needed for a V2 group */ + GROUP_V2_ADD, + + /** A message request is needed for an individual */ + INDIVIDUAL +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestViewModel.java index b3623fcdc..e48c3762a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestViewModel.java @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.util.SingleLiveEvent; import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; import org.thoughtcrime.securesms.util.livedata.LiveDataTriple; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; -import org.whispersystems.libsignal.util.Pair; import java.util.Collections; import java.util.List; @@ -39,7 +38,6 @@ public class MessageRequestViewModel extends ViewModel { private final LiveData messageData; private final MutableLiveData> groups = new MutableLiveData<>(Collections.emptyList()); private final MutableLiveData memberCount = new MutableLiveData<>(GroupMemberCount.ZERO); - private final MutableLiveData displayState = new MutableLiveData<>(); private final LiveData requestReviewDisplayState; private final LiveData recipientInfo = Transformations.map(new LiveDataTriple<>(recipient, memberCount, groups), triple -> new RecipientInfo(triple.first(), triple.second(), triple.third())); @@ -50,7 +48,6 @@ public class MessageRequestViewModel extends ViewModel { private long threadId; private final RecipientForeverObserver recipientObserver = recipient -> { - loadMessageRequestAccepted(recipient); loadMemberCount(); this.recipient.setValue(recipient); }; @@ -58,8 +55,7 @@ public class MessageRequestViewModel extends ViewModel { private MessageRequestViewModel(MessageRequestRepository repository) { this.repository = repository; this.messageData = LiveDataUtil.mapAsync(recipient, this::createMessageDataForRecipient); - this.requestReviewDisplayState = LiveDataUtil.mapAsync(LiveDataUtil.combineLatest(messageData, displayState, MessageDataDisplayStateHolder::new), - MessageRequestViewModel::transformHolderToReviewDisplayState); + this.requestReviewDisplayState = LiveDataUtil.mapAsync(messageData, MessageRequestViewModel::transformHolderToReviewDisplayState); } public void setConversationInfo(@NonNull RecipientId recipientId, long threadId) { @@ -82,10 +78,6 @@ public class MessageRequestViewModel extends ViewModel { } } - public LiveData getMessageRequestDisplayState() { - return displayState; - } - public LiveData getRequestReviewDisplayState() { return requestReviewDisplayState; } @@ -111,7 +103,8 @@ public class MessageRequestViewModel extends ViewModel { } public boolean shouldShowMessageRequest() { - return displayState.getValue() == DisplayState.DISPLAY_MESSAGE_REQUEST; + MessageData data = messageData.getValue(); + return data != null && data.getMessageState() != MessageRequestState.NONE; } @MainThread @@ -173,11 +166,10 @@ public class MessageRequestViewModel extends ViewModel { repository.getMemberCount(liveRecipient.getId(), memberCount::postValue); } - private static RequestReviewDisplayState transformHolderToReviewDisplayState(@NonNull MessageDataDisplayStateHolder holder) { - if (holder.messageData.messageClass == MessageClass.INDIVIDUAL && holder.displayState == DisplayState.DISPLAY_MESSAGE_REQUEST) { - return ReviewUtil.isRecipientReviewSuggested(holder.messageData.getRecipient().getId()) - ? RequestReviewDisplayState.SHOWN - : RequestReviewDisplayState.HIDDEN; + private static RequestReviewDisplayState transformHolderToReviewDisplayState(@NonNull MessageData holder) { + if (holder.getMessageState() == MessageRequestState.INDIVIDUAL) { + return ReviewUtil.isRecipientReviewSuggested(holder.getRecipient().getId()) ? RequestReviewDisplayState.SHOWN + : RequestReviewDisplayState.HIDDEN; } else { return RequestReviewDisplayState.NONE; } @@ -185,63 +177,8 @@ public class MessageRequestViewModel extends ViewModel { @WorkerThread private @NonNull MessageData createMessageDataForRecipient(@NonNull Recipient recipient) { - if (recipient.isBlocked()) { - if (recipient.isGroup()) { - return new MessageData(recipient, MessageClass.BLOCKED_GROUP); - } else { - return new MessageData(recipient, MessageClass.BLOCKED_INDIVIDUAL); - } - } else if (recipient.isPushV2Group()) { - if (repository.isPendingMember(recipient.requireGroupId().requireV2())) { - return new MessageData(recipient, MessageClass.GROUP_V2_INVITE); - } else { - return new MessageData(recipient, MessageClass.GROUP_V2_ADD); - } - } else if (recipient.isPushV1Group() && FeatureFlags.groupsV1ForcedMigration()) { - if (recipient.getParticipants().size() > FeatureFlags.groupLimits().getHardLimit()) { - return new MessageData(recipient, MessageClass.DEPRECATED_GROUP_V1_TOO_LARGE); - } else { - return new MessageData(recipient, MessageClass.DEPRECATED_GROUP_V1); - } - } else if (isLegacyThread(recipient)) { - if (recipient.isGroup()) { - return new MessageData(recipient, MessageClass.LEGACY_GROUP_V1); - } else { - return new MessageData(recipient, MessageClass.LEGACY_INDIVIDUAL); - } - } else if (recipient.isGroup()) { - return new MessageData(recipient, MessageClass.GROUP_V1); - } else { - return new MessageData(recipient, MessageClass.INDIVIDUAL); - } - } - - @SuppressWarnings("ConstantConditions") - private void loadMessageRequestAccepted(@NonNull Recipient recipient) { - if (recipient.isBlocked()) { - displayState.postValue(DisplayState.DISPLAY_MESSAGE_REQUEST); - return; - } - - repository.getMessageRequestState(recipient, threadId, accepted -> { - switch (accepted) { - case NOT_REQUIRED: - displayState.postValue(DisplayState.DISPLAY_NONE); - break; - case REQUIRED: - displayState.postValue(DisplayState.DISPLAY_MESSAGE_REQUEST); - break; - } - }); - } - - @WorkerThread - private boolean isLegacyThread(@NonNull Recipient recipient) { - Context context = ApplicationDependencies.getApplication(); - Long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient.getId()); - - return threadId != null && - (RecipientUtil.hasSentMessageInThread(context, threadId) || RecipientUtil.isPreMessageRequestThread(context, threadId)); + MessageRequestState state = repository.getMessageRequestState(recipient, threadId); + return new MessageData(recipient, state); } public static class RecipientInfo { @@ -284,27 +221,6 @@ public class MessageRequestViewModel extends ViewModel { ACCEPTED } - public enum DisplayState { - DISPLAY_MESSAGE_REQUEST, DISPLAY_NONE - } - - public enum MessageClass { - BLOCKED_INDIVIDUAL, - BLOCKED_GROUP, - /** An individual conversation that existed pre-message-requests but doesn't have profile sharing enabled */ - LEGACY_INDIVIDUAL, - /** A V1 group conversation that existed pre-message-requests but doesn't have profile sharing enabled */ - LEGACY_GROUP_V1, - /** A V1 group conversation that is no longer allowed, because we've forced GV2 on. */ - DEPRECATED_GROUP_V1, - /** A V1 group conversation that is no longer allowed, because we've forced GV2 on, but it's also too large to migrate. Nothing we can do. */ - DEPRECATED_GROUP_V1_TOO_LARGE, - GROUP_V1, - GROUP_V2_INVITE, - GROUP_V2_ADD, - INDIVIDUAL - } - public enum RequestReviewDisplayState { HIDDEN, SHOWN, @@ -313,29 +229,19 @@ public class MessageRequestViewModel extends ViewModel { public static final class MessageData { private final Recipient recipient; - private final MessageClass messageClass; + private final MessageRequestState messageState; - public MessageData(@NonNull Recipient recipient, @NonNull MessageClass messageClass) { + public MessageData(@NonNull Recipient recipient, @NonNull MessageRequestState messageState) { this.recipient = recipient; - this.messageClass = messageClass; + this.messageState = messageState; } public @NonNull Recipient getRecipient() { return recipient; } - public @NonNull MessageClass getMessageClass() { - return messageClass; - } - } - - private static final class MessageDataDisplayStateHolder { - private final MessageData messageData; - private final DisplayState displayState; - - private MessageDataDisplayStateHolder(@NonNull MessageData messageData, @NonNull DisplayState displayState) { - this.messageData = messageData; - this.displayState = displayState; + public @NonNull MessageRequestState getMessageState() { + return messageState; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestsBottomView.java b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestsBottomView.java index 68211fe1e..cb003bdf1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestsBottomView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagerequests/MessageRequestsBottomView.java @@ -4,7 +4,6 @@ import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.Button; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; @@ -74,7 +73,7 @@ public class MessageRequestsBottomView extends ConstraintLayout { question.setLearnMoreVisible(false); question.setOnLinkClickListener(null); - switch (messageData.getMessageClass()) { + switch (messageData.getMessageState()) { case BLOCKED_INDIVIDUAL: 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(recipient.getShortDisplayName(getContext()))), 0)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java index 1cf83c6b3..fda4248a3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java @@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.ThreadPhotoRailView; import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp; +import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.groups.ui.GroupMemberListView; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity; @@ -52,6 +53,7 @@ import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.LifecycleCursorWrapper; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.Util; +import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; import java.util.Locale; import java.util.Objects; @@ -69,7 +71,9 @@ public class ManageRecipientFragment extends LoggingFragment { private Toolbar toolbar; private TextView title; private TextView subtitle; - private TextView internalDetails; + private ViewGroup internalDetails; + private TextView internalDetailsText; + private View disableProfileSharingButton; private View contactRow; private TextView contactText; private ImageView contactIcon; @@ -128,6 +132,8 @@ public class ManageRecipientFragment extends LoggingFragment { title = view.findViewById(R.id.name); subtitle = view.findViewById(R.id.username_number); internalDetails = view.findViewById(R.id.recipient_internal_details); + internalDetailsText = view.findViewById(R.id.recipient_internal_details_text); + disableProfileSharingButton = view.findViewById(R.id.recipient_internal_details_disable_profile_sharing_button); sharedGroupList = view.findViewById(R.id.shared_group_list); groupsInCommonCount = view.findViewById(R.id.groups_in_common_count); threadPhotoRailView = view.findViewById(R.id.recent_photos); @@ -218,7 +224,10 @@ public class ManageRecipientFragment extends LoggingFragment { viewModel.getCanAddToAGroup().observe(getViewLifecycleOwner(), canAdd -> addToAGroup.setVisibility(canAdd ? View.VISIBLE : View.GONE)); if (SignalStore.internalValues().recipientDetails()) { - viewModel.getInternalDetails().observe(getViewLifecycleOwner(), internalDetails::setText); + viewModel.getInternalDetails().observe(getViewLifecycleOwner(), internalDetailsText::setText); + disableProfileSharingButton.setOnClickListener(v -> { + SignalExecutors.BOUNDED.execute(() -> DatabaseFactory.getRecipientDatabase(requireContext()).setProfileSharing(recipientId, false)); + }); internalDetails.setVisibility(View.VISIBLE); } else { internalDetails.setVisibility(View.GONE); diff --git a/app/src/main/res/layout/recipient_manage_fragment.xml b/app/src/main/res/layout/recipient_manage_fragment.xml index d18437592..5d0ecb3fa 100644 --- a/app/src/main/res/layout/recipient_manage_fragment.xml +++ b/app/src/main/res/layout/recipient_manage_fragment.xml @@ -55,17 +55,35 @@ android:textColor="@color/signal_text_secondary" tools:text="\@spidergwen +1 555-654-6657" /> - + android:visibility="gone" + tools:visibility="visible"> + + + + + + Network Force censorship Force the app to behave as if it is in a country where Signal is censored. - Conversations and Shortcuts - Delete all dynamic shortcuts - Click to delete all dynamic shortcuts + Conversations and Shortcuts + Delete all dynamic shortcuts + Click to delete all dynamic shortcuts + Disable Profile Sharing