feat: adding support for new closed groups, moving closed groups to be legacy throughout app
This commit is contained in:
parent
4e0d043a8c
commit
eaddc44de1
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -52,7 +52,7 @@ class ContactSelectionListLoader(context: Context, val mode: Int, val filter: St
|
|||
|
||||
private fun getClosedGroups(contacts: List<Recipient>): List<ContactSelectionListItem> {
|
||||
return getItems(contacts, context.getString(R.string.fragment_contact_selection_closed_groups_title)) {
|
||||
it.address.isClosedGroup
|
||||
it.address.isLegacyClosedGroup || it.address.isClosedGroup
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
) {
|
||||
|
|
|
@ -11,23 +11,29 @@ object MentionManagerUtilities {
|
|||
fun populateUserPublicKeyCacheIfNeeded(threadID: Long, context: Context) {
|
||||
val result = mutableSetOf<String>()
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -124,7 +124,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, 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
|
||||
|
|
|
@ -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<Int> = 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)
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ class Address private constructor(address: String) : Parcelable, Comparable<Addr
|
|||
constructor(`in`: Parcel) : this(`in`.readString()!!) {}
|
||||
|
||||
val isGroup: Boolean
|
||||
get() = GroupUtil.isEncodedGroup(address)
|
||||
val isClosedGroup: Boolean
|
||||
get() = GroupUtil.isClosedGroup(address)
|
||||
get() = GroupUtil.isEncodedGroup(address) || address.startsWith(IdPrefix.GROUP.value)
|
||||
val isLegacyClosedGroup: Boolean
|
||||
get() = GroupUtil.isLegacyClosedGroup(address)
|
||||
val isOpenGroup: Boolean
|
||||
get() = GroupUtil.isOpenGroup(address)
|
||||
val isOpenGroupInbox: Boolean
|
||||
|
|
|
@ -23,8 +23,8 @@ class GroupRecord(
|
|||
|
||||
val isOpenGroup: Boolean
|
||||
get() = Address.fromSerialized(encodedId).isOpenGroup
|
||||
val isClosedGroup: Boolean
|
||||
get() = Address.fromSerialized(encodedId).isClosedGroup
|
||||
val isLegacyClosedGroup: Boolean
|
||||
get() = Address.fromSerialized(encodedId).isLegacyClosedGroup
|
||||
|
||||
init {
|
||||
if (!TextUtils.isEmpty(members)) {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package org.session.libsession.utilities
|
||||
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import org.session.libsignal.messages.SignalServiceGroup
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import java.io.IOException
|
||||
|
||||
object GroupUtil {
|
||||
const val CLOSED_GROUP_PREFIX = "__textsecure_group__!"
|
||||
const val LEGACY_CLOSED_GROUP_PREFIX = "__textsecure_group__!"
|
||||
const val OPEN_GROUP_PREFIX = "__loki_public_chat_group__!"
|
||||
const val OPEN_GROUP_INBOX_PREFIX = "__open_group_inbox__!"
|
||||
|
||||
|
@ -22,7 +21,7 @@ object GroupUtil {
|
|||
|
||||
@JvmStatic
|
||||
fun getEncodedClosedGroupID(groupID: ByteArray): String {
|
||||
return CLOSED_GROUP_PREFIX + Hex.toStringCondensed(groupID)
|
||||
return LEGACY_CLOSED_GROUP_PREFIX + Hex.toStringCondensed(groupID)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -61,7 +60,7 @@ object GroupUtil {
|
|||
}
|
||||
|
||||
fun isEncodedGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX) || groupId.startsWith(OPEN_GROUP_PREFIX)
|
||||
return groupId.startsWith(LEGACY_CLOSED_GROUP_PREFIX) || groupId.startsWith(OPEN_GROUP_PREFIX)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@ -75,8 +74,8 @@ object GroupUtil {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isClosedGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(CLOSED_GROUP_PREFIX)
|
||||
fun isLegacyClosedGroup(groupId: String): Boolean {
|
||||
return groupId.startsWith(LEGACY_CLOSED_GROUP_PREFIX)
|
||||
}
|
||||
|
||||
// NOTE: Signal group ID handling is weird. The ID is double encoded in the database, but not in a `GroupContext`.
|
||||
|
|
|
@ -455,10 +455,11 @@ public class Recipient implements RecipientModifiedListener {
|
|||
return address.isOpenGroupInbox();
|
||||
}
|
||||
|
||||
public boolean isClosedGroupRecipient() {
|
||||
return address.isClosedGroup();
|
||||
public boolean isLegacyClosedGroupRecipient() {
|
||||
return address.isLegacyClosedGroup();
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public boolean isPushGroupRecipient() {
|
||||
return address.isGroup();
|
||||
|
|
Loading…
Reference in New Issue