From 8e313f83873d24cdbc4c29d64a84942e62ab58e6 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 18 Jan 2023 10:49:47 -0400 Subject: [PATCH] Collapse KnownRecipient / Story into single model. --- .../GiftFlowRecipientSelectionFragment.kt | 3 +- .../contacts/paged/ContactSearchData.kt | 4 +- .../contacts/paged/ContactSearchKey.kt | 53 ++--------------- .../contacts/paged/ContactSearchMediator.kt | 2 +- .../contacts/paged/ContactSearchRepository.kt | 3 +- .../contacts/paged/ContactSearchViewModel.kt | 2 +- .../contacts/paged/SafetyNumberRepository.kt | 6 +- .../ConversationParentFragment.java | 4 +- .../forward/MultiselectForwardActivity.kt | 4 +- .../forward/MultiselectForwardFragment.kt | 10 ++-- .../forward/MultiselectForwardRepository.kt | 4 +- .../securesms/jobs/GiftSendJob.kt | 2 +- .../mediasend/v2/MediaSelectionDestination.kt | 10 ++-- .../v2/stories/ChooseGroupStoryBottomSheet.kt | 4 +- .../text/send/TextStoryPostSendRepository.kt | 2 +- .../safety/SafetyNumberBottomSheet.kt | 12 ++-- .../safety/SafetyNumberBottomSheetArgs.kt | 2 +- .../SafetyNumberBottomSheetViewModel.kt | 2 +- .../securesms/sharing/MultiShareArgs.java | 14 ++--- .../securesms/sharing/v2/ShareActivity.kt | 5 +- .../stories/viewer/AddToGroupStoryDelegate.kt | 2 +- .../reply/group/StoryGroupReplyFragment.kt | 4 +- .../reply/group/StoryGroupReplySender.kt | 2 +- .../paged/ContactSearchPagedDataSourceTest.kt | 58 +++++++++---------- .../paged/SafetyNumberRepositoryTest.kt | 16 ++--- 25 files changed, 93 insertions(+), 137 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt index f03df2685f..1daee4a81e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowRecipientSelectionFragment.kt @@ -79,8 +79,7 @@ class GiftFlowRecipientSelectionFragment : Fragment(R.layout.gift_flow_recipient override fun onSearchInputFocused() = Unit override fun setResult(bundle: Bundle) { - val parcelableContacts: List = bundle.getParcelableArrayList(MultiselectForwardFragment.RESULT_SELECTION)!! - val contacts = parcelableContacts.map { it.asRecipientSearchKey() } + val contacts: List = bundle.getParcelableArrayList(MultiselectForwardFragment.RESULT_SELECTION)!! if (contacts.isNotEmpty()) { viewModel.setSelectedContact(contacts.first()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt index 7651806f2b..2ed57d774b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt @@ -18,7 +18,7 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) { val recipient: Recipient, val count: Int, val privacyMode: DistributionListPrivacyMode - ) : ContactSearchData(ContactSearchKey.RecipientSearchKey.Story(recipient.id)) + ) : ContactSearchData(ContactSearchKey.RecipientSearchKey(recipient.id, true)) /** * A row displaying a known recipient. @@ -27,7 +27,7 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) { val recipient: Recipient, val shortSummary: Boolean = false, val headerLetter: String? = null - ) : ContactSearchData(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.id)) + ) : ContactSearchData(ContactSearchKey.RecipientSearchKey(recipient.id, false)) /** * A row containing a title for a given section diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchKey.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchKey.kt index ae29c0e8ca..eed3dded19 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchKey.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchKey.kt @@ -12,44 +12,18 @@ sealed class ContactSearchKey { /** * Generates a ShareContact object used to display which contacts have been selected. This should *not* - * be used for the final sharing process, as it is not always truthful about, for example, KnownRecipient of + * be used for the final sharing process, as it is not always truthful about, for example, * a group vs. a group's Story. */ open fun requireShareContact(): ShareContact = error("This key cannot be converted into a ShareContact") - open fun requireParcelable(): ParcelableRecipientSearchKey = error("This key cannot be parcelized") + open fun requireRecipientSearchKey(): RecipientSearchKey = error("This key cannot be parcelized") - sealed class RecipientSearchKey : ContactSearchKey() { + @Parcelize + data class RecipientSearchKey(val recipientId: RecipientId, val isStory: Boolean) : ContactSearchKey(), Parcelable { + override fun requireRecipientSearchKey(): RecipientSearchKey = this - abstract val recipientId: RecipientId - abstract val isStory: Boolean - - data class Story(override val recipientId: RecipientId) : RecipientSearchKey() { - override fun requireShareContact(): ShareContact { - return ShareContact(recipientId) - } - - override fun requireParcelable(): ParcelableRecipientSearchKey { - return ParcelableRecipientSearchKey(ParcelableType.STORY, recipientId) - } - - override val isStory: Boolean = true - } - - /** - * Key to a recipient which already exists in our database - */ - data class KnownRecipient(override val recipientId: RecipientId) : RecipientSearchKey() { - override fun requireShareContact(): ShareContact { - return ShareContact(recipientId) - } - - override fun requireParcelable(): ParcelableRecipientSearchKey { - return ParcelableRecipientSearchKey(ParcelableType.KNOWN_RECIPIENT, recipientId) - } - - override val isStory: Boolean = false - } + override fun requireShareContact(): ShareContact = ShareContact(recipientId) } /** @@ -61,19 +35,4 @@ sealed class ContactSearchKey { * Key to an expand button for a given section */ data class Expand(val sectionKey: ContactSearchConfiguration.SectionKey) : ContactSearchKey() - - @Parcelize - data class ParcelableRecipientSearchKey(val type: ParcelableType, val recipientId: RecipientId) : Parcelable { - fun asRecipientSearchKey(): RecipientSearchKey { - return when (type) { - ParcelableType.STORY -> RecipientSearchKey.Story(recipientId) - ParcelableType.KNOWN_RECIPIENT -> RecipientSearchKey.KnownRecipient(recipientId) - } - } - } - - enum class ParcelableType { - STORY, - KNOWN_RECIPIENT - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchMediator.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchMediator.kt index 801b3f5c12..f20c7cd103 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchMediator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchMediator.kt @@ -90,7 +90,7 @@ class ContactSearchMediator( return viewModel.errorEventsStream.observeOn(AndroidSchedulers.mainThread()) } - fun addToVisibleGroupStories(groupStories: Set) { + fun addToVisibleGroupStories(groupStories: Set) { viewModel.addToVisibleGroupStories(groupStories) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchRepository.kt index 7e32edd7a6..148137b7c1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchRepository.kt @@ -21,8 +21,7 @@ class ContactSearchRepository { val isSelectable = when (it) { is ContactSearchKey.Expand -> false is ContactSearchKey.Header -> false - is ContactSearchKey.RecipientSearchKey.KnownRecipient -> canSelectRecipient(it.recipientId) - is ContactSearchKey.RecipientSearchKey.Story -> canSelectRecipient(it.recipientId) + is ContactSearchKey.RecipientSearchKey -> canSelectRecipient(it.recipientId) } ContactSearchSelectionResult(it, isSelectable) }.toSet() diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt index 585996cc32..4bdb4f600b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt @@ -98,7 +98,7 @@ class ContactSearchViewModel( return selectionStore.state } - fun addToVisibleGroupStories(groupStories: Set) { + fun addToVisibleGroupStories(groupStories: Set) { disposables += contactSearchRepository.markDisplayAsStory(groupStories.map { it.recipientId }).subscribe { configurationStore.update { state -> state.copy( diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt index 5d755b4082..7c77398946 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt @@ -77,8 +77,8 @@ class SafetyNumberRepository( private fun List.flattenToRecipientIds(): Set { return this .map { - when (it) { - is ContactSearchKey.RecipientSearchKey.KnownRecipient -> { + when { + it is ContactSearchKey.RecipientSearchKey && !it.isStory -> { val recipient = Recipient.resolved(it.recipientId) if (recipient.isGroup) { recipient.participantIds @@ -86,7 +86,7 @@ class SafetyNumberRepository( listOf(it.recipientId) } } - is ContactSearchKey.RecipientSearchKey.Story -> Recipient.resolved(it.recipientId).participantIds + it is ContactSearchKey.RecipientSearchKey -> Recipient.resolved(it.recipientId).participantIds else -> throw AssertionError("Invalid contact selection $it") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index 5a2aeb7826..56e5c2fa25 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -1570,7 +1570,7 @@ public class ConversationParentFragment extends Fragment SafetyNumberBottomSheet .forIdentityRecordsAndDestination( records, - new ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.getId()) + new ContactSearchKey.RecipientSearchKey(recipient.getId(), false) ) .show(getChildFragmentManager()); } @@ -3584,7 +3584,7 @@ public class ConversationParentFragment extends Fragment } @Override - public void sendAnywayAfterSafetyNumberChangedInBottomSheet(@NonNull List destinations) { + public void sendAnywayAfterSafetyNumberChangedInBottomSheet(@NonNull List destinations) { Log.d(TAG, "onSendAnywayAfterSafetyNumberChange"); initializeIdentityRecords().addListener(new AssertedSuccessListener() { @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardActivity.kt index b689c76fe5..dada7a5119 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardActivity.kt @@ -73,8 +73,8 @@ open class MultiselectForwardActivity : FragmentWrapperActivity(), MultiselectFo } else if (intent == null || !intent.hasExtra(RESULT_SELECTION)) { throw IllegalStateException("Selection contract requires a selection.") } else { - val selection: List = intent.getParcelableArrayListExtra(RESULT_SELECTION)!! - selection.map { it.asRecipientSearchKey() } + val selection: List = intent.getParcelableArrayListExtra(RESULT_SELECTION)!! + selection } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt index f718d53e2b..ce7b9e1123 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragment.kt @@ -191,7 +191,7 @@ class MultiselectForwardFragment : shareSelectionAdapter.submitList(contactSelection.mapIndexed { index, key -> ShareSelectionMappingModel(key.requireShareContact(), index == 0) }) - addMessage.visible = !args.forceDisableAddMessage && contactSelection.any { key -> key !is ContactSearchKey.RecipientSearchKey.Story } && args.multiShareArgs.isNotEmpty() + addMessage.visible = !args.forceDisableAddMessage && contactSelection.any { key -> !key.requireRecipientSearchKey().isStory } && args.multiShareArgs.isNotEmpty() if (contactSelection.isNotEmpty() && !bottomBar.isVisible) { bottomBar.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_fade_from_bottom) @@ -237,13 +237,13 @@ class MultiselectForwardFragment : setFragmentResultListener(CreateStoryWithViewersFragment.REQUEST_KEY) { _, bundle -> val recipientId: RecipientId = bundle.getParcelable(CreateStoryWithViewersFragment.STORY_RECIPIENT)!! - contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.RecipientSearchKey.Story(recipientId))) + contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.RecipientSearchKey(recipientId, true))) contactFilterView.clear() } setFragmentResultListener(ChooseGroupStoryBottomSheet.GROUP_STORY) { _, bundle -> val groups: Set = bundle.getParcelableArrayList(ChooseGroupStoryBottomSheet.RESULT_SET)?.toSet() ?: emptySet() - val keys: Set = groups.map { ContactSearchKey.RecipientSearchKey.Story(it) }.toSet() + val keys: Set = groups.map { ContactSearchKey.RecipientSearchKey(it, true) }.toSet() contactSearchMediator.addToVisibleGroupStories(keys) contactSearchMediator.setKeysSelected(keys) contactFilterView.clear() @@ -350,7 +350,7 @@ class MultiselectForwardFragment : dismissibleDialog?.dismiss() val resultsBundle = Bundle().apply { - putParcelableArrayList(RESULT_SELECTION, ArrayList(selectedContacts.map { it.requireParcelable() })) + putParcelableArrayList(RESULT_SELECTION, ArrayList(selectedContacts.map { it.requireRecipientSearchKey() })) } callback.setResult(resultsBundle) @@ -489,7 +489,7 @@ class MultiselectForwardFragment : } override fun onMyStoryConfigured(recipientId: RecipientId) { - contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.RecipientSearchKey.Story(recipientId))) + contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.RecipientSearchKey(recipientId, true))) contactSearchMediator.refresh() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardRepository.kt index 684b611688..df8ef252bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardRepository.kt @@ -62,14 +62,14 @@ class MultiselectForwardRepository { SignalExecutors.BOUNDED.execute { val filteredContacts: Set = shareContacts .asSequence() - .filter { it is ContactSearchKey.RecipientSearchKey.Story || it is ContactSearchKey.RecipientSearchKey.KnownRecipient } + .filter { it is ContactSearchKey.RecipientSearchKey } .toSet() val mappedArgs: List = multiShareArgs.map { it.buildUpon(filteredContacts).build() } val results = mappedArgs.sortedBy { it.timestamp }.map { MultiShareSender.sendSync(it) } if (additionalMessage.isNotEmpty()) { - val additional = MultiShareArgs.Builder(filteredContacts.filterNot { it is ContactSearchKey.RecipientSearchKey.Story }.toSet()) + val additional = MultiShareArgs.Builder(filteredContacts.filterNot { it is ContactSearchKey.RecipientSearchKey && it.isStory }.toSet()) .withDraftText(additionalMessage) .build() diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt index 2e7cfec79a..f6b42118f0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GiftSendJob.kt @@ -80,7 +80,7 @@ class GiftSendJob private constructor(parameters: Parameters, private val recipi Log.i(TAG, "Sending additional message...") val result = MultiShareSender.sendSync( - MultiShareArgs.Builder(setOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipientId))) + MultiShareArgs.Builder(setOf(ContactSearchKey.RecipientSearchKey(recipientId, false))) .withDraftText(trimmedMessage) .build() ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionDestination.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionDestination.kt index b9e730ec9b..414603ceca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionDestination.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionDestination.kt @@ -29,7 +29,7 @@ sealed class MediaSelectionDestination { } class SingleRecipient(private val id: RecipientId) : MediaSelectionDestination() { - override fun getRecipientSearchKey(): ContactSearchKey.RecipientSearchKey = ContactSearchKey.RecipientSearchKey.KnownRecipient(id) + override fun getRecipientSearchKey(): ContactSearchKey.RecipientSearchKey = ContactSearchKey.RecipientSearchKey(id, false) override fun toBundle(): Bundle { return Bundle().apply { @@ -39,7 +39,7 @@ sealed class MediaSelectionDestination { } class SingleStory(private val id: RecipientId) : MediaSelectionDestination() { - override fun getRecipientSearchKey(): ContactSearchKey.RecipientSearchKey = ContactSearchKey.RecipientSearchKey.Story(id) + override fun getRecipientSearchKey(): ContactSearchKey.RecipientSearchKey = ContactSearchKey.RecipientSearchKey(id, true) override fun toBundle(): Bundle { return Bundle().apply { @@ -51,8 +51,8 @@ sealed class MediaSelectionDestination { class MultipleRecipients(val recipientSearchKeys: List) : MediaSelectionDestination() { companion object { - fun fromParcel(parcelables: List): MultipleRecipients { - return MultipleRecipients(parcelables.map { it.asRecipientSearchKey() }.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java)) + fun fromParcel(parcelables: List): MultipleRecipients { + return MultipleRecipients(parcelables) } } @@ -68,7 +68,7 @@ sealed class MediaSelectionDestination { override fun toBundle(): Bundle { return Bundle().apply { - putParcelableArrayList(RECIPIENT_LIST, ArrayList(recipientSearchKeys.map { it.requireParcelable() })) + putParcelableArrayList(RECIPIENT_LIST, ArrayList(recipientSearchKeys.map { it.requireRecipientSearchKey() })) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt index 04645b4824..1bc40033ed 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt @@ -86,7 +86,7 @@ class ChooseGroupStoryBottomSheet : FixedRoundedCornerBottomSheetDialogFragment( mediator.getSelectionState().observe(viewLifecycleOwner) { state -> adapter.submitList( - state.filterIsInstance(ContactSearchKey.RecipientSearchKey.KnownRecipient::class.java) + state.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java) .map { it.recipientId } .mapIndexed { index, recipientId -> ShareSelectionMappingModel( @@ -146,7 +146,7 @@ class ChooseGroupStoryBottomSheet : FixedRoundedCornerBottomSheetDialogFragment( RESULT_SET, ArrayList( mediator.getSelectedContacts() - .filterIsInstance(ContactSearchKey.RecipientSearchKey.KnownRecipient::class.java) + .filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java) .map { it.recipientId } ) ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt index 436dbe9548..d8b8265ec6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt @@ -64,7 +64,7 @@ class TextStoryPostSendRepository { for (contact in contactSearchKey) { val recipient = Recipient.resolved(contact.requireShareContact().recipientId.get()) - val isStory = contact is ContactSearchKey.RecipientSearchKey.Story || recipient.isDistributionList + val isStory = contact.requireRecipientSearchKey().isStory || recipient.isDistributionList if (isStory && !recipient.isMyStory) { SignalStore.storyValues().setLatestStorySend(StorySend.newSend(recipient)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt index e2ad384e4c..e965937819 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt @@ -99,7 +99,7 @@ object SafetyNumberBottomSheet { fun forIdentityRecordsAndDestinations(identityRecords: List, destinations: List): Factory { val args = SafetyNumberBottomSheetArgs( identityRecords.map { it.recipientId }, - destinations.filterIsInstance().map { it.requireParcelable() } + destinations.filterIsInstance().map { it.requireRecipientSearchKey() } ) return SheetFactory(args) @@ -115,7 +115,7 @@ object SafetyNumberBottomSheet { fun forIdentityRecordsAndDestination(identityRecords: List, destination: ContactSearchKey): Factory { val args = SafetyNumberBottomSheetArgs( identityRecords.map { it.recipientId }, - listOf(destination).filterIsInstance().map { it.requireParcelable() } + listOf(destination).filterIsInstance().map { it.requireRecipientSearchKey() } ) return SheetFactory(args) @@ -131,14 +131,14 @@ object SafetyNumberBottomSheet { return args!! } - private fun getDestinationFromRecord(messageRecord: MessageRecord): List { + private fun getDestinationFromRecord(messageRecord: MessageRecord): List { val key = if ((messageRecord as? MmsMessageRecord)?.storyType?.isStory == true) { - ContactSearchKey.RecipientSearchKey.Story(messageRecord.recipient.id) + ContactSearchKey.RecipientSearchKey(messageRecord.recipient.id, true) } else { - ContactSearchKey.RecipientSearchKey.KnownRecipient(messageRecord.recipient.id) + ContactSearchKey.RecipientSearchKey(messageRecord.recipient.id, false) } - return listOf(key.requireParcelable()) + return listOf(key) } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetArgs.kt b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetArgs.kt index 7f7d96b420..e2a578564b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetArgs.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetArgs.kt @@ -12,6 +12,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId @Parcelize data class SafetyNumberBottomSheetArgs( val untrustedRecipients: List, - val destinations: List, + val destinations: List, val messageId: MessageId? = null ) : Parcelable diff --git a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetViewModel.kt index 2066277fa9..c3ff782e4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheetViewModel.kt @@ -25,7 +25,7 @@ class SafetyNumberBottomSheetViewModel( private const val MAX_RECIPIENTS_TO_DISPLAY = 5 } - private val destinationStore = RxStore(args.destinations.map { it.asRecipientSearchKey() }) + private val destinationStore = RxStore(args.destinations) val destinationSnapshot: List get() = destinationStore.state diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java index 923dbc5191..8e0f54d49d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java @@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.util.Util; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -61,11 +62,9 @@ public final class MultiShareArgs implements Parcelable { } protected MultiShareArgs(Parcel in) { - List parcelableRecipientSearchKeys = in.createTypedArrayList(ContactSearchKey.ParcelableRecipientSearchKey.CREATOR); + List parcelableRecipientSearchKeys = in.createTypedArrayList(ContactSearchKey.RecipientSearchKey.CREATOR); - contactSearchKeys = parcelableRecipientSearchKeys.stream() - .map(ContactSearchKey.ParcelableRecipientSearchKey::asRecipientSearchKey) - .collect(Collectors.toSet()); + contactSearchKeys = new HashSet<>(parcelableRecipientSearchKeys); media = in.createTypedArrayList(Media.CREATOR); draftText = in.readString(); stickerLocator = in.readParcelable(StickerLocator.class.getClassLoader()); @@ -197,7 +196,8 @@ public final class MultiShareArgs implements Parcelable { } public boolean allRecipientsAreStories() { - return !contactSearchKeys.isEmpty() && contactSearchKeys.stream().allMatch(key -> key instanceof ContactSearchKey.RecipientSearchKey.Story); + return !contactSearchKeys.isEmpty() && contactSearchKeys.stream() + .allMatch(key -> key.requireRecipientSearchKey().isStory()); } public static final Creator CREATOR = new Creator() { @@ -219,7 +219,7 @@ public final class MultiShareArgs implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeTypedList(Stream.of(contactSearchKeys).map(ContactSearchKey::requireParcelable).toList()); + dest.writeTypedList(Stream.of(contactSearchKeys).map(ContactSearchKey::requireRecipientSearchKey).toList()); dest.writeTypedList(media); dest.writeString(draftText); dest.writeParcelable(stickerLocator, flags); @@ -267,7 +267,7 @@ public final class MultiShareArgs implements Parcelable { (!media.isEmpty() || !TextUtils.isEmpty(draftText) || MediaUtil.isImageOrVideoType(dataType) || - (!contactSearchKeys.isEmpty() && contactSearchKeys.stream().anyMatch(key -> key instanceof ContactSearchKey.RecipientSearchKey.Story))); + (!contactSearchKeys.isEmpty() && contactSearchKeys.stream().anyMatch(key -> key.requireRecipientSearchKey().isStory()))); } public static final class Builder { diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/v2/ShareActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/sharing/v2/ShareActivity.kt index 2dfbd9bdcb..6a5075bc7b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/v2/ShareActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/v2/ShareActivity.kt @@ -103,7 +103,7 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C openConversation( ShareEvent.OpenConversation( shareState.loadState.resolvedShareData, - ContactSearchKey.RecipientSearchKey.KnownRecipient(directShareTarget) + ContactSearchKey.RecipientSearchKey(directShareTarget, false) ) ) } else { @@ -134,8 +134,7 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C throw AssertionError("Expected a recipient selection!") } - val parcelizedKeys: List = bundle.getParcelableArrayList(MultiselectForwardFragment.RESULT_SELECTION)!! - val contactSearchKeys = parcelizedKeys.map { it.asRecipientSearchKey() } + val contactSearchKeys: List = bundle.getParcelableArrayList(MultiselectForwardFragment.RESULT_SELECTION)!! viewModel.onContactSelectionConfirmed(contactSearchKeys) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/AddToGroupStoryDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/AddToGroupStoryDelegate.kt index 764f999429..0a81ca6ffb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/AddToGroupStoryDelegate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/AddToGroupStoryDelegate.kt @@ -128,7 +128,7 @@ class AddToGroupStoryDelegate( private fun sendNonPreUploadedMedia(result: MediaSendActivityResult) { Log.d(TAG, "Sending non-preupload media.") - val multiShareArgs = MultiShareArgs.Builder(setOf(ContactSearchKey.RecipientSearchKey.Story(result.recipientId))) + val multiShareArgs = MultiShareArgs.Builder(setOf(ContactSearchKey.RecipientSearchKey(result.recipientId, true))) .withMedia(result.nonUploadedMedia.toList()) .withDraftText(result.body) .withMentions(result.mentions.toList()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt index 537faaae20..318e6b1431 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt @@ -387,7 +387,7 @@ class StoryGroupReplyFragment : resendReaction = emoji SafetyNumberBottomSheet - .forIdentityRecordsAndDestination(error.untrustedRecords, ContactSearchKey.RecipientSearchKey.Story(groupRecipientId)) + .forIdentityRecordsAndDestination(error.untrustedRecords, ContactSearchKey.RecipientSearchKey(groupRecipientId, true)) .show(childFragmentManager) } else { Log.w(TAG, "Failed to send reply", error) @@ -536,7 +536,7 @@ class StoryGroupReplyFragment : resendMentions = mentions SafetyNumberBottomSheet - .forIdentityRecordsAndDestination(throwable.untrustedRecords, ContactSearchKey.RecipientSearchKey.Story(groupRecipientId)) + .forIdentityRecordsAndDestination(throwable.untrustedRecords, ContactSearchKey.RecipientSearchKey(groupRecipientId, true)) .show(childFragmentManager) } else { Log.w(TAG, "Failed to send reply", throwable) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt index 8e9a741dba..e26b0e559a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt @@ -36,7 +36,7 @@ object StoryGroupReplySender { } return messageAndRecipient.flatMapCompletable { (message, recipient) -> - UntrustedRecords.checkForBadIdentityRecords(setOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.id)), System.currentTimeMillis() - IdentityRecordList.DEFAULT_UNTRUSTED_WINDOW) + UntrustedRecords.checkForBadIdentityRecords(setOf(ContactSearchKey.RecipientSearchKey(recipient.id, false)), System.currentTimeMillis() - IdentityRecordList.DEFAULT_UNTRUSTED_WINDOW) .andThen( Completable.create { MessageSender.send( diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt index 6a43b1d571..ef6a70b92b 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt @@ -51,16 +51,16 @@ class ContactSearchPagedDataSourceTest { val expected = listOf( ContactSearchKey.Header(ContactSearchConfiguration.SectionKey.RECENTS), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), ContactSearchKey.Header(ContactSearchConfiguration.SectionKey.INDIVIDUALS) ) @@ -75,15 +75,15 @@ class ContactSearchPagedDataSourceTest { val result = testSubject.load(5, 10) { false } val expected = listOf( - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), ContactSearchKey.Header(ContactSearchConfiguration.SectionKey.INDIVIDUALS), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.KnownRecipient(RecipientId.UNKNOWN), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, false), ContactSearchKey.Expand(ContactSearchConfiguration.SectionKey.INDIVIDUALS) ) @@ -99,17 +99,17 @@ class ContactSearchPagedDataSourceTest { val expected = listOf( ContactSearchKey.Header(ContactSearchConfiguration.SectionKey.STORIES), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), - ContactSearchKey.RecipientSearchKey.Story(RecipientId.UNKNOWN), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), + ContactSearchKey.RecipientSearchKey(RecipientId.UNKNOWN, true), ) val resultKeys = result.map { it.contactSearchKey } diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt index f8ec47e01f..b4d6b84048 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepositoryTest.kt @@ -108,7 +108,7 @@ class SafetyNumberRepositoryTest { @Test fun batchSafetyNumberCheckSync_batchOf1_noChanges() { val other = recipientPool[1] - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) @@ -127,7 +127,7 @@ class SafetyNumberRepositoryTest { val other = recipientPool[1] val otherAci = ACI.from(other.requireServiceId()) val otherNewIdentityKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) @@ -148,7 +148,7 @@ class SafetyNumberRepositoryTest { val secondOther = recipientPool[2] val otherAci = ACI.from(other.requireServiceId()) val otherNewIdentityKey = IdentityKeyUtil.generateIdentityKeyPair().publicKey - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id), ContactSearchKey.RecipientSearchKey.KnownRecipient(secondOther.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false), ContactSearchKey.RecipientSearchKey(secondOther.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other, secondOther)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey, secondOther.requireServiceId() to identityPool[secondOther]!!.identityKey))) @@ -166,7 +166,7 @@ class SafetyNumberRepositoryTest { @Test fun batchSafetyNumberCheckSync_batchOf1_abortOnPriorRecentCheck() { val other = recipientPool[1] - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) @@ -187,7 +187,7 @@ class SafetyNumberRepositoryTest { */ @Test fun batchSafetyNumberCheckSync_batchOf10WithSmallBatchSize_noChanges() { - val keys = recipientPool.map { ContactSearchKey.RecipientSearchKey.KnownRecipient(it.id) } + val keys = recipientPool.map { ContactSearchKey.RecipientSearchKey(it.id, false) } val others = recipientPool.subList(1, recipientPool.lastIndex) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(others.map { it.id }) }) }.thenReturn(others) @@ -205,7 +205,7 @@ class SafetyNumberRepositoryTest { @Test fun batchSafetyNumberCheckSync_serverError() { val other = recipientPool[1] - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) @@ -219,7 +219,7 @@ class SafetyNumberRepositoryTest { @Test fun batchSafetyNumberCheckSync_networkError() { val other = recipientPool[1] - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey))) @@ -233,7 +233,7 @@ class SafetyNumberRepositoryTest { @Test fun batchSafetyNumberCheckSync_badJson() { val other = recipientPool[1] - val keys = listOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(other.id)) + val keys = listOf(ContactSearchKey.RecipientSearchKey(other.id, false)) staticRecipient.`when`> { Recipient.resolvedList(argThat { containsAll(keys.map { it.recipientId }) }) }.thenReturn(listOf(other)) whenever(profileService.performIdentityCheck(mapOf(other.requireServiceId() to identityPool[other]!!.identityKey)))