From e2e3617be9a919b23b9f61f5c7e8069b288d50d3 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 4 Mar 2022 11:20:30 -0400 Subject: [PATCH] Ensure groups stories are sent to are retained in the UI. --- .../paged/ContactSearchPagedDataSource.kt | 3 +- .../ContactSearchPagedDataSourceRepository.kt | 7 +++ .../securesms/database/GroupDatabase.java | 43 ++++++++++++++++--- .../helpers/SignalDatabaseMigrations.kt | 7 ++- .../mediasend/v2/MediaSelectionRepository.kt | 5 ++- .../securesms/sharing/MultiShareSender.java | 5 ++- .../paged/ContactSearchPagedDataSourceTest.kt | 1 + 7 files changed, 60 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt index 485c7f8c6..06dd69b0c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt @@ -90,7 +90,8 @@ class ContactSearchPagedDataSource( } private fun getFilteredGroupStories(section: ContactSearchConfiguration.Section.Stories, query: String?): List { - return section.groupStories.filter { contactSearchPagedDataSourceRepository.recipientNameContainsQuery(it.recipient, query) } + return (contactSearchPagedDataSourceRepository.getGroupStories() + section.groupStories) + .filter { contactSearchPagedDataSourceRepository.recipientNameContainsQuery(it.recipient, query) } } private fun getSectionData(section: ContactSearchConfiguration.Section, query: String?, startIndex: Int, endIndex: Int): List { diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt index b9add44a2..183e91726 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt @@ -72,6 +72,13 @@ open class ContactSearchPagedDataSourceRepository( return SignalDatabase.distributionLists.getMemberCount(recipient.requireDistributionListId()) } + open fun getGroupStories(): Set { + return SignalDatabase.groups.groupsToDisplayAsStories.map { + val recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromGroupId(it)) + ContactSearchData.Story(recipient, recipient.participants.size) + }.toSet() + } + open fun recipientNameContainsQuery(recipient: Recipient, query: String?): Boolean { return query.isNullOrBlank() || recipient.getDisplayName(context).contains(query) } 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 f57fdc59a..4b277a456 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -23,14 +23,13 @@ import org.signal.zkgroup.InvalidInputException; import org.signal.zkgroup.groups.GroupMasterKey; import org.thoughtcrime.securesms.crypto.SenderKeyUtil; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor; -import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob; -import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.whispersystems.signalservice.api.push.ACI; -import org.whispersystems.signalservice.api.push.DistributionId; +import org.thoughtcrime.securesms.groups.BadGroupIdException; import org.thoughtcrime.securesms.groups.GroupAccessControl; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange; +import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor; +import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.CursorUtil; @@ -41,6 +40,8 @@ import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import org.whispersystems.signalservice.api.groupsv2.GroupChangeReconstruct; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; +import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -81,6 +82,7 @@ public class GroupDatabase extends Database { private static final String EXPECTED_V2_ID = "expected_v2_id"; private static final String UNMIGRATED_V1_MEMBERS = "former_v1_members"; private static final String DISTRIBUTION_ID = "distribution_id"; + private static final String DISPLAY_AS_STORY = "display_as_story"; /* V2 Group columns */ @@ -109,13 +111,14 @@ public class GroupDatabase extends Database { V2_DECRYPTED_GROUP + " BLOB, " + EXPECTED_V2_ID + " TEXT DEFAULT NULL, " + UNMIGRATED_V1_MEMBERS + " TEXT DEFAULT NULL, " + - DISTRIBUTION_ID + " TEXT DEFAULT NULL);"; + DISTRIBUTION_ID + " TEXT DEFAULT NULL, " + + DISPLAY_AS_STORY + " INTEGER DEFAULT 0);"; public static final String[] CREATE_INDEXS = { "CREATE UNIQUE INDEX IF NOT EXISTS group_id_index ON " + TABLE_NAME + " (" + GROUP_ID + ");", "CREATE UNIQUE INDEX IF NOT EXISTS group_recipient_id_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ");", "CREATE UNIQUE INDEX IF NOT EXISTS expected_v2_id_index ON " + TABLE_NAME + " (" + EXPECTED_V2_ID + ");", - "CREATE UNIQUE INDEX IF NOT EXISTS group_distribution_id_index ON " + TABLE_NAME + "(" + DISTRIBUTION_ID + ")" + "CREATE UNIQUE INDEX IF NOT EXISTS group_distribution_id_index ON " + TABLE_NAME + "(" + DISTRIBUTION_ID + ");" }; private static final String[] GROUP_PROJECTION = { @@ -1349,6 +1352,32 @@ private static final String[] GROUP_PROJECTION = { } } + public @NonNull List getGroupsToDisplayAsStories() throws BadGroupIdException { + String[] selection = SqlUtil.buildArgs(GROUP_ID); + String where = DISPLAY_AS_STORY + " = ? AND " + ACTIVE + " = ?"; + String[] whereArgs = SqlUtil.buildArgs(1, 1); + + try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, selection, where, whereArgs, null, null, null, null)) { + if (cursor == null || cursor.getCount() == 0) { + return Collections.emptyList(); + } + + List results = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { + results.add(GroupId.parse(CursorUtil.requireString(cursor, GROUP_ID))); + } + + return results; + } + } + + public void markDisplayAsStory(@NonNull GroupId groupId) { + ContentValues contentValues = new ContentValues(1); + contentValues.put(DISPLAY_AS_STORY, true); + + getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?", SqlUtil.buildArgs(groupId.toString())); + } + public enum MemberSet { FULL_MEMBERS_INCLUDING_SELF(true, false), FULL_MEMBERS_EXCLUDING_SELF(false, false), diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 83635b94b..46e791b47 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -193,8 +193,9 @@ object SignalDatabaseMigrations { private const val DONATION_RECEIPTS = 131 private const val STORIES = 132 private const val ALLOW_STORY_REPLIES = 133 + private const val GROUP_STORIES = 134 - const val DATABASE_VERSION = 133 + const val DATABASE_VERSION = 134 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { @@ -2476,6 +2477,10 @@ object SignalDatabaseMigrations { if (oldVersion < ALLOW_STORY_REPLIES) { db.execSQL("ALTER TABLE distribution_list ADD COLUMN allows_replies INTEGER DEFAULT 1") } + + if (oldVersion < GROUP_STORIES) { + db.execSQL("ALTER TABLE groups ADD COLUMN display_as_story INTEGER DEFAULT 0") + } } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt index 7b5eabe98..06d5bebd8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt @@ -39,7 +39,6 @@ import org.thoughtcrime.securesms.scribbles.ImageEditorFragment import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.sms.MessageSender.PreUploadResult import org.thoughtcrime.securesms.util.MessageUtil -import java.util.ArrayList import java.util.Collections import java.util.concurrent.TimeUnit @@ -205,6 +204,10 @@ class MediaSelectionRepository(context: Context) { val recipient = Recipient.resolved(contact.recipientId) val isStory = contact is ContactSearchKey.Story || recipient.isDistributionList + if (isStory && recipient.isActiveGroup) { + SignalDatabase.groups.markDisplayAsStory(recipient.requireGroupId()) + } + val storyType: StoryType = when { recipient.isDistributionList -> SignalDatabase.distributionLists.getStoryType(recipient.requireDistributionListId()) isStory -> StoryType.STORY_WITH_REPLIES diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java index bf2530e4c..f4f84c0df 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java @@ -32,7 +32,6 @@ import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.MessageUtil; -import org.thoughtcrime.securesms.util.ParcelUtil; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; @@ -181,6 +180,10 @@ public final class MultiShareSender { storyType = StoryType.STORY_WITH_REPLIES; } + if (recipient.isActiveGroup()) { + SignalDatabase.groups().markDisplayAsStory(recipient.requireGroupId()); + } + for (final Slide slide : slideDeck.getSlides()) { SlideDeck singletonDeck = new SlideDeck(); singletonDeck.addSlide(slide); 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 14b89f92b..7a70293e4 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 @@ -28,6 +28,7 @@ class ContactSearchPagedDataSourceTest { `when`(repository.getRecipientFromRecipientCursor(cursor)).thenReturn(Recipient.UNKNOWN) `when`(repository.getRecipientFromThreadCursor(cursor)).thenReturn(Recipient.UNKNOWN) `when`(repository.getRecipientFromDistributionListCursor(cursor)).thenReturn(Recipient.UNKNOWN) + `when`(repository.getGroupStories()).thenReturn(emptySet()) `when`(cursor.moveToPosition(anyInt())).thenCallRealMethod() `when`(cursor.moveToNext()).thenCallRealMethod() `when`(cursor.position).thenCallRealMethod()