diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java index c2445fb7d..c5236f82d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.java @@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController; import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner; import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferLockedDialog; import org.thoughtcrime.securesms.keyvalue.SignalStore; +import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsState; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel; @@ -132,7 +133,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot } private void updateTabVisibility() { - if (FeatureFlags.stories() && !SignalStore.storyValues().isFeatureDisabled()) { + if (Stories.isFeatureEnabled()) { findViewById(R.id.conversation_list_tabs).setVisibility(View.VISIBLE); WindowUtil.setNavigationBarColor(getWindow(), ContextCompat.getColor(this, R.color.signal_background_secondary)); } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/avatar/view/AvatarView.kt b/app/src/main/java/org/thoughtcrime/securesms/avatar/view/AvatarView.kt index c100b36a3..b870d1776 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/avatar/view/AvatarView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/avatar/view/AvatarView.kt @@ -7,10 +7,9 @@ import android.widget.FrameLayout import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.AvatarImageView import org.thoughtcrime.securesms.database.model.StoryViewState -import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.recipients.Recipient -import org.thoughtcrime.securesms.util.FeatureFlags +import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.visible /** @@ -28,8 +27,8 @@ class AvatarView @JvmOverloads constructor( private val avatar: AvatarImageView = findViewById(R.id.avatar_image_view) private val storyRing: View = findViewById(R.id.avatar_story_ring) - fun showStoryRing(hasUnreadStory: Boolean) { - if (!FeatureFlags.stories() || SignalStore.storyValues().isFeatureDisabled) { + private fun showStoryRing(hasUnreadStory: Boolean) { + if (!Stories.isFeatureEnabled()) { return } @@ -40,7 +39,7 @@ class AvatarView @JvmOverloads constructor( avatar.scaleY = 0.82f } - fun hideStoryRing() { + private fun hideStoryRing() { storyRing.visible = false avatar.scaleX = 1f diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt index 4cba2473a..a861bcc30 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt @@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberL import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.service.KeyCachingService +import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.stories.settings.custom.PrivateStorySettingsFragmentArgs import org.thoughtcrime.securesms.stories.settings.story.PrivateStoryItem import org.thoughtcrime.securesms.util.CommunicationActions @@ -295,7 +296,7 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac summary = DSLSettingsText.from(incognitoSummary), ) - if (FeatureFlags.stories()) { + if (Stories.isFeatureAvailable()) { dividerPref() diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java index 70da81f05..85d7c4a5d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactsCursorLoader.java @@ -29,16 +29,13 @@ import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.DistributionListPartialRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord; -import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.phonenumbers.NumberUtil; -import org.thoughtcrime.securesms.recipients.RecipientId; +import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.UsernameUtil; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Set; /** * CursorLoader that initializes a ContactsDatabase instance @@ -171,7 +168,7 @@ public class ContactsCursorLoader extends AbstractContactsCursorLoader { } private void addStoriesSection(@NonNull List cursorList) { - if (!FeatureFlags.stories() || !storiesEnabled(mode) || SignalStore.storyValues().isFeatureDisabled()) { + if (!Stories.isFeatureEnabled() ||!storiesEnabled(mode)) { return; } 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 95e8977b0..75ef4f9ea 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 @@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.sharing.MultiShareArgs import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel +import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.stories.settings.create.CreateStoryFlowDialogFragment import org.thoughtcrime.securesms.stories.settings.create.CreateStoryWithViewersFragment import org.thoughtcrime.securesms.util.BottomSheetUtil @@ -269,7 +270,7 @@ class MultiselectForwardFragment : return ContactSearchConfiguration.build { query = contactSearchState.query - if (FeatureFlags.stories() && isSelectedMediaValidForStories()) { + if (Stories.isFeatureEnabled() && isSelectedMediaValidForStories()) { addSection( ContactSearchConfiguration.Section.Stories( groupStories = contactSearchState.groupStories, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index bf9ea8fbf..95ca97381 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -77,8 +77,8 @@ import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo; import org.thoughtcrime.securesms.revealable.ViewOnceUtil; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage; +import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.CursorUtil; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.SqlUtil; @@ -593,7 +593,7 @@ public class MmsDatabase extends MessageDatabase { @Override public @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId) { - if (!FeatureFlags.stories() || SignalStore.storyValues().isFeatureDisabled()) { + if (!Stories.isFeatureEnabled()) { return StoryViewState.NONE; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java index 3a689cac1..e0742dcd0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java @@ -168,7 +168,6 @@ public final class PushDistributionListSendJob extends PushSendJob { private List deliver(@NonNull OutgoingMediaMessage message, @NonNull List destinations) throws IOException, UntrustedIdentityException, UndeliverableMessageException { - // TODO [stories] Filter based off of stories capability try { rotateSenderCertificateIfNecessary(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 77a0698b7..4c9a2afd9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -241,7 +241,6 @@ public final class PushGroupSendJob extends PushSendJob { .anyMatch(info -> info.getStatus() > GroupReceiptDatabase.STATUS_UNDELIVERED); if (message.getStoryType().isStory()) { - // TODO [stories] Filter based off of stories capability Optional groupRecord = SignalDatabase.groups().getGroup(groupId); if (groupRecord.isPresent()) { @@ -308,6 +307,10 @@ public final class PushGroupSendJob extends PushSendJob { MessageRecord storyRecord = SignalDatabase.mms().getMessageRecord(message.getParentStoryId().asMessageId().getId()); Recipient recipient = storyRecord.isOutgoing() ? Recipient.self() : storyRecord.getIndividualRecipient(); + destinations = destinations.stream() + .filter(r -> r.getStoriesCapability() == Recipient.Capability.SUPPORTED) + .collect(java.util.stream.Collectors.toList()); + groupMessageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(recipient.requireServiceId(), storyRecord.getDateSent())); } catch (NoSuchMessageException e) { // The story has probably expired diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt index b5ea95765..e56796537 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt @@ -20,12 +20,12 @@ import org.thoughtcrime.securesms.TransportOptions import org.thoughtcrime.securesms.components.emoji.EmojiEventListener import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment -import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult import org.thoughtcrime.securesms.mediasend.v2.review.MediaReviewFragment import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationViewModel import org.thoughtcrime.securesms.recipients.RecipientId +import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.navigation.safeNavigate import org.thoughtcrime.securesms.util.visible @@ -104,9 +104,8 @@ class MediaSelectionActivity : } private fun canDisplayStorySwitch(): Boolean { - return FeatureFlags.stories() && + return Stories.isFeatureEnabled() && FeatureFlags.storiesTextPosts() && - !SignalStore.storyValues().isFeatureDisabled && isCameraFirst() && !viewModel.hasSelectedMedia() && destination == MediaSelectionDestination.ChooseAfterMediaSelection diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java b/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java index d3ae651ce..09a054be6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java @@ -160,7 +160,15 @@ public final class GroupSendUtil { @NonNull SignalServiceStoryMessage message) throws IOException, UntrustedIdentityException { - return sendMessage(context, null, getDistributionId(distributionListId), messageId, allTargets, isRecipientUpdate, new StorySendOperation(messageId, null, sentTimestamp, message), null); + return sendMessage( + context, + null, + getDistributionId(distributionListId), + messageId, + allTargets, + isRecipientUpdate, + new StorySendOperation(messageId, null, sentTimestamp, message), + null); } /** @@ -178,7 +186,15 @@ public final class GroupSendUtil { @NonNull SignalServiceStoryMessage message) throws IOException, UntrustedIdentityException { - return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, new StorySendOperation(messageId, groupId, sentTimestamp, message), null); + return sendMessage( + context, + groupId, + getDistributionId(groupId), + messageId, + allTargets, + isRecipientUpdate, + new StorySendOperation(messageId, groupId, sentTimestamp, message), + null); } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index 57d86d20d..0d95c8a1a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -115,6 +115,7 @@ import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.storage.StorageSyncHelper; +import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Hex; @@ -1319,6 +1320,11 @@ public final class MessageContentProcessor { private void handleStoryMessage(@NonNull SignalServiceContent content, @NonNull SignalServiceStoryMessage message, @NonNull Recipient senderRecipient) throws StorageFailedException { log(content.getTimestamp(), "Story message."); + if (Stories.isFeatureAvailable()) { + warn(content.getTimestamp(), "Dropping unsupported story."); + return; + } + Optional insertResult; MessageDatabase database = SignalDatabase.mms(); @@ -1379,6 +1385,11 @@ public final class MessageContentProcessor { private void handleStoryReply(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) throws StorageFailedException { log(content.getTimestamp(), "Story reply."); + if (!Stories.isFeatureAvailable()) { + warn(content.getTimestamp(), "Dropping unsupported story reply."); + return; + } + SignalServiceDataMessage.StoryContext storyContext = message.getStoryContext().get(); MessageDatabase database = SignalDatabase.mms(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt new file mode 100644 index 000000000..f5351efb5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt @@ -0,0 +1,17 @@ +package org.thoughtcrime.securesms.stories + +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.util.FeatureFlags + +object Stories { + @JvmStatic + fun isFeatureAvailable(): Boolean { + return FeatureFlags.stories() && Recipient.self().storiesCapability == Recipient.Capability.SUPPORTED + } + + @JvmStatic + fun isFeatureEnabled(): Boolean { + return isFeatureAvailable() && !SignalStore.storyValues().isFeatureDisabled + } +}