From eaddc44de1f578bc853ae78a3d1da47460273462 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Thu, 24 Aug 2023 17:38:14 +1000 Subject: [PATCH] feat: adding support for new closed groups, moving closed groups to be legacy throughout app --- .../securesms/MediaOverviewActivity.java | 5 -- .../components/ProfilePictureView.kt | 2 +- .../contacts/ContactSelectionListLoader.kt | 2 +- .../settings/ConversationSettingsActivity.kt | 5 +- .../settings/ConversationSettingsViewModel.kt | 8 +- .../conversation/v2/ConversationActivityV2.kt | 11 +-- .../v2/DeleteOptionsBottomSheet.kt | 2 +- .../conversation/v2/MessageDetailActivity.kt | 1 + .../conversation/v2/dialogs/DownloadDialog.kt | 10 +-- .../v2/menus/ConversationMenuHelper.kt | 8 +- .../v2/messages/VisibleMessageContentView.kt | 1 - .../v2/utilities/MentionManagerUtilities.kt | 38 +++++---- .../securesms/database/MmsDatabase.kt | 4 +- .../securesms/database/Storage.kt | 85 +++++++++++-------- .../securesms/database/ThreadDatabase.java | 4 +- .../dependencies/DatabaseBindings.kt | 17 ++++ .../dependencies/DatabaseComponent.kt | 2 +- .../util/ConfigurationMessageUtilities.kt | 6 +- .../messaging/jobs/ConfigurationSyncJob.kt | 4 +- .../messaging/messages/Destination.kt | 9 +- .../messages/control/ConfigurationMessage.kt | 2 +- .../sending_receiving/MessageSender.kt | 10 +-- .../session/libsession/utilities/Address.kt | 6 +- .../libsession/utilities/GroupRecord.kt | 4 +- .../session/libsession/utilities/GroupUtil.kt | 11 ++- .../utilities/recipients/Recipient.java | 5 +- 26 files changed, 150 insertions(+), 112 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseBindings.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java index e2dcbeb77..ae5824e86 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java @@ -20,7 +20,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; -import android.content.res.Resources; import android.database.Cursor; import android.os.Build; import android.os.Bundle; @@ -34,9 +33,7 @@ import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.Toolbar; @@ -53,7 +50,6 @@ import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; -import org.session.libsession.database.StorageProtocol; import org.session.libsession.messaging.MessagingModuleConfiguration; import org.session.libsession.messaging.messages.control.DataExtractionNotification; import org.session.libsession.messaging.sending_receiving.MessageSender; @@ -65,7 +61,6 @@ import org.session.libsession.utilities.Util; import org.session.libsession.utilities.ViewUtil; import org.session.libsession.utilities.recipients.Recipient; import org.session.libsession.utilities.task.ProgressDialogAsyncTask; -import org.thoughtcrime.securesms.conversation.settings.ClearAllMediaDialog; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.MediaDatabase; import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt index 604422460..81695e3bf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt @@ -54,7 +54,7 @@ class ProfilePictureView @JvmOverloads constructor( return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey } - if (recipient.isClosedGroupRecipient) { + if (recipient.isLegacyClosedGroupRecipient) { val members = DatabaseComponent.get(context).groupDatabase() .getGroupMemberAddresses(recipient.address.toGroupString(), true) .sorted() diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt index 3a2b2cbb5..34e25af0b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListLoader.kt @@ -52,7 +52,7 @@ class ContactSelectionListLoader(context: Context, val mode: Int, val filter: St private fun getClosedGroups(contacts: List): List { return getItems(contacts, context.getString(R.string.fragment_contact_selection_closed_groups_title)) { - it.address.isClosedGroup + it.address.isLegacyClosedGroup || it.address.isClosedGroup } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt index 8c1d74490..165666fc3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt @@ -60,7 +60,6 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View. super.onCreate(savedInstanceState, ready) binding = ActivityConversationSettingsBinding.inflate(layoutInflater) setContentView(binding.root) - binding.profilePictureView.root.glide = GlideApp.with(this) updateRecipientDisplay() binding.searchConversation.setOnClickListener(this) binding.clearMessages.setOnClickListener(this) @@ -91,7 +90,7 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View. } // Toggle group-specific settings - val areGroupOptionsVisible = recipient.isClosedGroupRecipient + val areGroupOptionsVisible = recipient.isClosedGroupRecipient || recipient.isLegacyClosedGroupRecipient groupOptions.forEach { v -> v.isVisible = areGroupOptionsVisible } @@ -164,7 +163,7 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View. } v === binding.editGroup -> { val recipient = viewModel.recipient ?: return - if (!recipient.isClosedGroupRecipient) return + if (!recipient.isClosedGroupRecipient || !recipient.isLegacyClosedGroupRecipient) return val intent = Intent(this, EditClosedGroupActivity::class.java) val groupID: String = recipient.address.toGroupString() intent.putExtra(EditClosedGroupActivity.groupIDKey, groupID) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt index c1bc18174..34b233b16 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt @@ -18,11 +18,11 @@ class ConversationSettingsViewModel( val recipient get() = storage.getRecipientForThread(threadId) - fun isPinned() = storage.isThreadPinned(threadId) + fun isPinned() = storage.isPinned(threadId) fun togglePin() = viewModelScope.launch { - val isPinned = storage.isThreadPinned(threadId) - storage.setThreadPinned(threadId, !isPinned) + val isPinned = storage.isPinned(threadId) + storage.setPinned(threadId, !isPinned) } fun autoDownloadAttachments() = recipient?.let { recipient -> storage.shouldAutoDownloadAttachments(recipient) } ?: false @@ -32,7 +32,7 @@ class ConversationSettingsViewModel( } fun isUserGroupAdmin(): Boolean = recipient?.let { recipient -> - if (!recipient.isClosedGroupRecipient) return@let false + if (!recipient.isLegacyClosedGroupRecipient || !recipient.isClosedGroupRecipient) return@let false val localUserAddress = prefs.getLocalNumber() ?: return@let false val group = storage.getGroup(recipient.address.toGroupString()) group?.admins?.contains(Address.fromSerialized(localUserAddress)) ?: false // this will have to be replaced for new closed groups diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 7f1947c91..fd2d300b5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -592,7 +592,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe recipient.isLocalNumber -> getString(R.string.note_to_self) else -> recipient.toShortString() } - @DimenRes val sizeID: Int = if (viewModel.recipient?.isClosedGroupRecipient == true) { + @DimenRes val sizeID: Int = if (viewModel.recipient?.isLegacyClosedGroupRecipient == true) { R.dimen.medium_profile_picture_size } else { R.dimen.small_profile_picture_size @@ -823,8 +823,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } private fun showOrHideInputIfNeeded() { - val recipient = viewModel.recipient - if (recipient != null && recipient.isClosedGroupRecipient) { + val recipient = viewModel.recipient ?: return + if (recipient.isLegacyClosedGroupRecipient) { val group = groupDb.getGroup(recipient.address.toGroupString()).orNull() val isActive = (group?.isActive == true) binding?.inputBar?.showInput = isActive @@ -1157,7 +1157,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } override fun onClick(v: View?) { - if (v === binding?.toolbarContent?.profilePictureView?.root) { + if (v === binding?.toolbarContent?.profilePictureView) { // open conversation settings conversationSettingsCallback.launch(viewModel.threadId) } @@ -1197,8 +1197,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show() } + // TODO: don't need to allow new closed group check here, removed in new disappearing messages override fun showExpiringMessagesDialog(thread: Recipient) { - if (thread.isClosedGroupRecipient) { + if (thread.isLegacyClosedGroupRecipient) { val group = groupDb.getGroup(thread.address.toGroupString()).orNull() if (group?.isActive == false) { return } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt index a2fdc73fd..c05f5d926 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt @@ -63,7 +63,7 @@ class DeleteOptionsBottomSheet : BottomSheetDialogFragment(), View.OnClickListen binding.deleteForEveryoneTextView.text = resources.getString(R.string.delete_message_for_me_and_recipient, contact) } - binding.deleteForEveryoneTextView.isVisible = !recipient.isClosedGroupRecipient + binding.deleteForEveryoneTextView.isVisible = !recipient.isLegacyClosedGroupRecipient binding.deleteForMeTextView.setOnClickListener(this) binding.deleteForEveryoneTextView.setOnClickListener(this) binding.cancelTextView.setOnClickListener(this) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt index b0d5e992a..c316a2ae5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt @@ -55,6 +55,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import network.loki.messenger.R import network.loki.messenger.databinding.ViewVisibleMessageContentBinding +import org.session.libsession.database.StorageProtocol import org.thoughtcrime.securesms.MediaPreviewActivity.getPreviewIntent import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.database.Storage diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt index ceb9410df..f2d17af56 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt @@ -9,7 +9,6 @@ import android.text.style.StyleSpan import androidx.fragment.app.DialogFragment import dagger.hilt.android.AndroidEntryPoint import network.loki.messenger.R -import network.loki.messenger.databinding.DialogDownloadBinding import org.session.libsession.database.StorageProtocol import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment @@ -31,20 +30,21 @@ class AutoDownloadDialog(private val threadRecipient: Recipient, override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = createSessionDialog { val threadId = storage.getThreadId(threadRecipient) ?: run { dismiss() - return + return@createSessionDialog } val displayName = when { threadRecipient.isOpenGroupRecipient -> storage.getOpenGroup(threadId)?.name ?: "UNKNOWN" - threadRecipient.isClosedGroupRecipient -> storage.getGroup(threadRecipient.address.toGroupString())?.title ?: "UNKNOWN" + threadRecipient.isLegacyClosedGroupRecipient -> storage.getGroup(threadRecipient.address.toGroupString())?.title ?: "UNKNOWN" + // TODO: threadRecipient.isClosedGroupRecipient -> storage.getLibSessionGroup(threadRecipient.address.serialize())?.groupName ?: "UNKNOWN" or something else -> storage.getContactWithSessionID(threadRecipient.address.serialize())?.displayName(Contact.ContactContext.REGULAR) ?: "UNKNOWN" } title(resources.getString(R.string.dialog_auto_download_title)) val explanation = resources.getString(R.string.dialog_auto_download_explanation, displayName) val spannable = SpannableStringBuilder(explanation) - val startIndex = explanation.indexOf(name) - spannable.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + name.count(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + val startIndex = explanation.indexOf(displayName) + spannable.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + displayName.count(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) text(spannable) button(R.string.dialog_download_button_title, R.string.AccessibilityId_download_media) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 02ee4ae45..5dcfc8afd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -63,7 +63,7 @@ object ConversationMenuHelper { // Base menu (options that should always be present) inflater.inflate(R.menu.menu_conversation, menu) // Expiring messages - if (!isOpenGroup && (thread.hasApprovedMe() || thread.isClosedGroupRecipient) && !thread.isBlocked) { + if (!isOpenGroup && (thread.hasApprovedMe() || thread.isLegacyClosedGroupRecipient) && !thread.isBlocked) { if (thread.expireMessages > 0) { inflater.inflate(R.menu.menu_conversation_expiration_on, menu) val item = menu.findItem(R.id.menu_expiring_messages) @@ -92,7 +92,7 @@ object ConversationMenuHelper { } } // Closed group menu (options that should only be present in closed groups) - if (thread.isClosedGroupRecipient) { + if (thread.isLegacyClosedGroupRecipient) { inflater.inflate(R.menu.menu_conversation_closed_group, menu) } // Open group menu @@ -280,7 +280,7 @@ object ConversationMenuHelper { } private fun editClosedGroup(context: Context, thread: Recipient) { - if (!thread.isClosedGroupRecipient) { return } + if (!thread.isLegacyClosedGroupRecipient) { return } val intent = Intent(context, EditClosedGroupActivity::class.java) val groupID: String = thread.address.toGroupString() intent.putExtra(groupIDKey, groupID) @@ -288,7 +288,7 @@ object ConversationMenuHelper { } private fun leaveClosedGroup(context: Context, thread: Recipient) { - if (!thread.isClosedGroupRecipient) { return } + if (!thread.isLegacyClosedGroupRecipient) { return } val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull() val admins = group.admins diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index d23656616..1e47ba075 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -64,7 +64,6 @@ class VisibleMessageContentView : ConstraintLayout { glide: GlideRequests = GlideApp.with(this), thread: Recipient, searchQuery: String? = null, - contactIsTrusted: Boolean = true, onAttachmentNeedsDownload: (Long, Long) -> Unit, suppressThumbnails: Boolean = false ) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionManagerUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionManagerUtilities.kt index ee1c7257c..f7f7e784f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionManagerUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/MentionManagerUtilities.kt @@ -11,23 +11,29 @@ object MentionManagerUtilities { fun populateUserPublicKeyCacheIfNeeded(threadID: Long, context: Context) { val result = mutableSetOf() val recipient = DatabaseComponent.get(context).threadDatabase().getRecipientForThreadId(threadID) ?: return - if (recipient.address.isClosedGroup) { - val members = DatabaseComponent.get(context).groupDatabase().getGroupMembers(recipient.address.toGroupString(), false).map { it.address.serialize() } - result.addAll(members) - } else { - val messageDatabase = DatabaseComponent.get(context).mmsSmsDatabase() - val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID, true, 0, 200)) - var record: MessageRecord? = reader.next - while (record != null) { - result.add(record.individualRecipient.address.serialize()) - try { - record = reader.next - } catch (exception: Exception) { - record = null - } + when { + recipient.address.isLegacyClosedGroup -> { + val members = DatabaseComponent.get(context).groupDatabase().getGroupMembers(recipient.address.toGroupString(), false).map { it.address.serialize() } + result.addAll(members) + } + recipient.address.isClosedGroup -> { + TODO("get members from libsession via storage") + } + recipient.address.isOpenGroup -> { + val messageDatabase = DatabaseComponent.get(context).mmsSmsDatabase() + val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID, true, 0, 200)) + var record: MessageRecord? = reader.next + while (record != null) { + result.add(record.individualRecipient.address.serialize()) + try { + record = reader.next + } catch (exception: Exception) { + record = null + } + } + reader.close() + result.add(TextSecurePreferences.getLocalNumber(context)!!) } - reader.close() - result.add(TextSecurePreferences.getLocalNumber(context)!!) } MentionsManager.userPublicKeyCache[threadID] = result } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index d14e63217..8555b248d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -932,7 +932,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa cursor?.close() } val threadDb = get(context).threadDatabase() - threadDb.update(threadId, false) + threadDb.update(threadId, false, false) notifyConversationListeners(threadId) notifyStickerListeners() notifyStickerPackListeners() @@ -959,7 +959,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa cursor?.close() } val threadDb = get(context).threadDatabase() - threadDb.update(threadId, false) + threadDb.update(threadId, false, true) notifyConversationListeners(threadId) notifyStickerListeners() notifyStickerPackListeners() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index f42cfc00e..b0e4eb6d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -5,6 +5,7 @@ import android.net.Uri import network.loki.messenger.libsession_util.ConfigBase import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_PINNED +import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_VISIBLE import network.loki.messenger.libsession_util.Contacts import network.loki.messenger.libsession_util.ConversationVolatileConfig import network.loki.messenger.libsession_util.UserGroupsConfig @@ -101,20 +102,26 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co val volatile = configFactory.convoVolatile ?: return if (address.isGroup) { val groups = configFactory.userGroups ?: return - if (address.isClosedGroup) { - val sessionId = GroupUtil.doubleDecodeGroupId(address.serialize()) - val closedGroup = getGroup(address.toGroupString()) - if (closedGroup != null && closedGroup.isActive) { - val legacyGroup = groups.getOrConstructLegacyGroupInfo(sessionId) - groups.set(legacyGroup) - val newVolatileParams = volatile.getOrConstructLegacyGroup(sessionId).copy( - lastRead = SnodeAPI.nowWithOffset, - ) - volatile.set(newVolatileParams) + when { + address.isLegacyClosedGroup -> { + val sessionId = GroupUtil.doubleDecodeGroupId(address.serialize()) + val closedGroup = getGroup(address.toGroupString()) + if (closedGroup != null && closedGroup.isActive) { + val legacyGroup = groups.getOrConstructLegacyGroupInfo(sessionId) + groups.set(legacyGroup) + val newVolatileParams = volatile.getOrConstructLegacyGroup(sessionId).copy( + lastRead = SnodeAPI.nowWithOffset, + ) + volatile.set(newVolatileParams) + } + } + address.isClosedGroup -> { + Log.w("Loki", "Thread created called for new closed group address, not adding any extra information") + } + address.isOpenGroup -> { + // these should be added on the group join / group info fetch + Log.w("Loki", "Thread created called for open group address, not adding any extra information") } - } else if (address.isOpenGroup) { - // these should be added on the group join / group info fetch - Log.w("Loki", "Thread created called for open group address, not adding any extra information") } } else if (address.isContact) { // non-standard contact prefixes: 15, 00 etc shouldn't be stored in config @@ -123,11 +130,11 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co if (getUserPublicKey() != address.serialize()) { val contacts = configFactory.contacts ?: return contacts.upsertContact(address.serialize()) { - priority = ConfigBase.PRIORITY_VISIBLE + priority = PRIORITY_VISIBLE } } else { val userProfile = configFactory.user ?: return - userProfile.setNtsPriority(ConfigBase.PRIORITY_VISIBLE) + userProfile.setNtsPriority(PRIORITY_VISIBLE) DatabaseComponent.get(context).threadDatabase().setHasSent(threadId, true) } val newVolatileParams = volatile.getOrConstructOneToOne(address.serialize()) @@ -241,7 +248,8 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co configFactory.convoVolatile?.let { config -> val convo = when { // recipient closed group - recipient.isClosedGroupRecipient -> config.getOrConstructLegacyGroup(GroupUtil.doubleDecodeGroupId(recipient.address.serialize())) + recipient.isLegacyClosedGroupRecipient -> config.getOrConstructLegacyGroup(GroupUtil.doubleDecodeGroupId(recipient.address.serialize())) + recipient.isClosedGroupRecipient -> config.getOrConstructGroup(recipient.address.serialize()) // recipient is open group recipient.isOpenGroupRecipient -> { val openGroupJoinUrl = getOpenGroup(threadId)?.joinURL ?: return @@ -848,7 +856,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co sessionId = groupPublicKey, name = name, members = members, - priority = ConfigBase.PRIORITY_VISIBLE, + priority = PRIORITY_VISIBLE, encPubKey = (encryptionKeyPair.publicKey as DjbECPublicKey).publicKey, // 'serialize()' inserts an extra byte encSecKey = encryptionKeyPair.privateKey.serialize(), disappearingTimer = 0L, @@ -884,7 +892,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co members = membersMap, encPubKey = (latestKeyPair.publicKey as DjbECPublicKey).publicKey, // 'serialize()' inserts an extra byte encSecKey = latestKeyPair.privateKey.serialize(), - priority = if (isPinned(threadID)) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE, + priority = if (isPinned(threadID)) PRIORITY_PINNED else PRIORITY_VISIBLE, disappearingTimer = recipientSettings.expireMessages.toLong(), joinedAt = (existingGroup.formationTimestamp / 1000L) ) @@ -1264,27 +1272,36 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co val threadRecipient = getRecipientForThread(threadID) ?: return if (threadRecipient.isLocalNumber) { val user = configFactory.user ?: return - user.setNtsPriority(if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE) + user.setNtsPriority(if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE) } else if (threadRecipient.isContactRecipient) { val contacts = configFactory.contacts ?: return contacts.upsertContact(threadRecipient.address.serialize()) { - priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE + priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE } } else if (threadRecipient.isGroupRecipient) { val groups = configFactory.userGroups ?: return - if (threadRecipient.isClosedGroupRecipient) { - val sessionId = GroupUtil.doubleDecodeGroupId(threadRecipient.address.serialize()) - val newGroupInfo = groups.getOrConstructLegacyGroupInfo(sessionId).copy ( - priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE - ) - groups.set(newGroupInfo) - } else if (threadRecipient.isOpenGroupRecipient) { - val openGroup = getOpenGroup(threadID) ?: return - val (baseUrl, room, pubKeyHex) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return - val newGroupInfo = groups.getOrConstructCommunityInfo(baseUrl, room, Hex.toStringCondensed(pubKeyHex)).copy ( - priority = if (isPinned) PRIORITY_PINNED else ConfigBase.PRIORITY_VISIBLE - ) - groups.set(newGroupInfo) + when { + threadRecipient.isLegacyClosedGroupRecipient -> { + val sessionId = GroupUtil.doubleDecodeGroupId(threadRecipient.address.serialize()) + val newGroupInfo = groups.getOrConstructLegacyGroupInfo(sessionId).copy ( + priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE + ) + groups.set(newGroupInfo) + } + threadRecipient.isClosedGroupRecipient -> { + val newGroupInfo = groups.getGroupInfo(threadRecipient.address.serialize()).copy ( + priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE + ) + groups.set(newGroupInfo) + } + threadRecipient.isOpenGroupRecipient -> { + val openGroup = getOpenGroup(threadID) ?: return + val (baseUrl, room, pubKeyHex) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return + val newGroupInfo = groups.getOrConstructCommunityInfo(baseUrl, room, Hex.toStringCondensed(pubKeyHex)).copy ( + priority = if (isPinned) PRIORITY_PINNED else PRIORITY_VISIBLE + ) + groups.set(newGroupInfo) + } } } ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context) @@ -1341,7 +1358,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co } else { smsDb.deleteMessagesFrom(threadID, fromUser.serialize()) mmsDb.deleteMessagesFrom(threadID, fromUser.serialize()) - threadDb.update(threadID, false) + threadDb.update(threadID, false, true) } return true } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index bd425ed93..d358e323d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -17,7 +17,7 @@ */ package org.thoughtcrime.securesms.database; -import static org.session.libsession.utilities.GroupUtil.CLOSED_GROUP_PREFIX; +import static org.session.libsession.utilities.GroupUtil.LEGACY_CLOSED_GROUP_PREFIX; import static org.session.libsession.utilities.GroupUtil.OPEN_GROUP_PREFIX; import static org.thoughtcrime.securesms.database.GroupDatabase.GROUP_ID; @@ -503,7 +503,7 @@ public class ThreadDatabase extends Database { } public Cursor getApprovedConversationList() { - String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+CLOSED_GROUP_PREFIX+"%') OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " + + String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+ LEGACY_CLOSED_GROUP_PREFIX +"%') OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " + "AND " + ARCHIVED + " = 0 "; return getConversationList(where); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseBindings.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseBindings.kt new file mode 100644 index 000000000..5a1dee052 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseBindings.kt @@ -0,0 +1,17 @@ +package org.thoughtcrime.securesms.dependencies + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.session.libsession.database.StorageProtocol +import org.thoughtcrime.securesms.database.Storage + +@Module +@InstallIn(SingletonComponent::class) +abstract class DatabaseBindings { + + @Binds + abstract fun bindStorageProtocol(storage: Storage): StorageProtocol + +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt index eddd61c83..d37aa5ce2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt @@ -42,7 +42,7 @@ interface DatabaseComponent { fun sessionContactDatabase(): SessionContactDatabase fun reactionDatabase(): ReactionDatabase fun emojiSearchDatabase(): EmojiSearchDatabase - fun storage(): StorageProtocol + fun storage(): Storage fun attachmentProvider(): MessageDataProvider fun blindedIdMappingDatabase(): BlindedIdMappingDatabase fun groupMemberDatabase(): GroupMemberDatabase diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt index 297014d86..abbf73ff4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ConfigurationMessageUtilities.kt @@ -273,13 +273,13 @@ object ConfigurationMessageUtilities { @JvmField val DELETE_INACTIVE_GROUPS: String = """ - DELETE FROM ${GroupDatabase.TABLE_NAME} WHERE ${GroupDatabase.GROUP_ID} IN (SELECT ${ThreadDatabase.ADDRESS} FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%'); - DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.ADDRESS} IN (SELECT ${ThreadDatabase.ADDRESS} FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%'); + DELETE FROM ${GroupDatabase.TABLE_NAME} WHERE ${GroupDatabase.GROUP_ID} IN (SELECT ${ThreadDatabase.ADDRESS} FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} LIKE '${GroupUtil.LEGACY_CLOSED_GROUP_PREFIX}%'); + DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.ADDRESS} IN (SELECT ${ThreadDatabase.ADDRESS} FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} LIKE '${GroupUtil.LEGACY_CLOSED_GROUP_PREFIX}%'); """.trimIndent() @JvmField val DELETE_INACTIVE_ONE_TO_ONES: String = """ - DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.CLOSED_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_INBOX_PREFIX}%'; + DELETE FROM ${ThreadDatabase.TABLE_NAME} WHERE ${ThreadDatabase.MESSAGE_COUNT} <= 0 AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.LEGACY_CLOSED_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_PREFIX}%' AND ${ThreadDatabase.ADDRESS} NOT LIKE '${GroupUtil.OPEN_GROUP_INBOX_PREFIX}%'; """.trimIndent() } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt index ec8de4416..fe4df6b72 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/ConfigurationSyncJob.kt @@ -157,14 +157,14 @@ data class ConfigurationSyncJob(val destination: Destination): Job { fun Destination.destinationPublicKey(): String = when (this) { is Destination.Contact -> publicKey - is Destination.ClosedGroup -> groupPublicKey + is Destination.ClosedGroup -> publicKey else -> throw NullPointerException("Not public key for this destination") } override fun serialize(): Data { val (type, address) = when (destination) { is Destination.Contact -> CONTACT_TYPE to destination.publicKey - is Destination.ClosedGroup -> GROUP_TYPE to destination.groupPublicKey + is Destination.ClosedGroup -> GROUP_TYPE to destination.publicKey else -> return Data.EMPTY } return Data.Builder() diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt index f30c1b916..25fa6284b 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt @@ -10,12 +10,15 @@ sealed class Destination { data class Contact(var publicKey: String) : Destination() { internal constructor(): this("") } - data class ClosedGroup(var groupPublicKey: String) : Destination() { + data class LegacyClosedGroup(var groupPublicKey: String) : Destination() { internal constructor(): this("") } data class LegacyOpenGroup(var roomToken: String, var server: String) : Destination() { internal constructor(): this("", "") } + data class ClosedGroup(var publicKey: String): Destination() { + internal constructor(): this("") + } class OpenGroup( var roomToken: String = "", @@ -38,10 +41,10 @@ sealed class Destination { address.isContact -> { Contact(address.contactIdentifier()) } - address.isClosedGroup -> { + address.isLegacyClosedGroup -> { val groupID = address.toGroupString() val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupID).toHexString() - ClosedGroup(groupPublicKey) + LegacyClosedGroup(groupPublicKey) } address.isOpenGroup -> { val storage = MessagingModuleConfiguration.shared.storage diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt index eae9a7673..9c876fb0c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ConfigurationMessage.kt @@ -124,7 +124,7 @@ class ConfigurationMessage(var closedGroups: List, var openGroups: val profileKey = ProfileKeyUtil.getProfileKey(context) val groups = storage.getAllGroups(includeInactive = false) for (group in groups) { - if (group.isClosedGroup && group.isActive) { + if (group.isLegacyClosedGroup && group.isActive) { if (!group.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString() val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index be7075dc5..b80b2088f 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -87,7 +87,7 @@ object MessageSender { when (destination) { is Destination.Contact -> message.recipient = destination.publicKey - is Destination.ClosedGroup -> message.recipient = destination.groupPublicKey + is Destination.LegacyClosedGroup -> message.recipient = destination.groupPublicKey else -> throw IllegalStateException("Destination should not be an open group.") } @@ -126,7 +126,7 @@ object MessageSender { // Encrypt the serialized protobuf val ciphertext = when (destination) { is Destination.Contact -> MessageEncrypter.encrypt(plaintext, destination.publicKey) - is Destination.ClosedGroup -> { + is Destination.LegacyClosedGroup -> { val encryptionKeyPair = MessagingModuleConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair( destination.groupPublicKey @@ -143,7 +143,7 @@ object MessageSender { kind = SignalServiceProtos.Envelope.Type.SESSION_MESSAGE senderPublicKey = "" } - is Destination.ClosedGroup -> { + is Destination.LegacyClosedGroup -> { kind = SignalServiceProtos.Envelope.Type.CLOSED_GROUP_MESSAGE senderPublicKey = destination.groupPublicKey } @@ -183,9 +183,9 @@ object MessageSender { // TODO: this might change in future for config messages val forkInfo = SnodeAPI.forkInfo val namespaces: List = when { - destination is Destination.ClosedGroup + destination is Destination.LegacyClosedGroup && forkInfo.defaultRequiresAuth() -> listOf(Namespace.UNAUTHENTICATED_CLOSED_GROUP) - destination is Destination.ClosedGroup + destination is Destination.LegacyClosedGroup && forkInfo.hasNamespaces() -> listOf(Namespace.UNAUTHENTICATED_CLOSED_GROUP, Namespace.DEFAULT) else -> listOf(Namespace.DEFAULT) } diff --git a/libsession/src/main/java/org/session/libsession/utilities/Address.kt b/libsession/src/main/java/org/session/libsession/utilities/Address.kt index c8cd11d4b..805166e1c 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/Address.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/Address.kt @@ -20,9 +20,9 @@ class Address private constructor(address: String) : Parcelable, Comparable