mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-21 15:05:19 +00:00
[SES-1002] Synced blind requests (#1303)
* feat: update config to use blinded-msg-requests pr * feat: add block community message requests bool to protos * feat: add everything needed for recipientDB to have blocked community requests potentially * feat: add db migrations * feat: add sending community block flags and preference options * feat: add parsing block request flag * fix: open group message requests were broken anyway * fix: delete all encoded open group inbox ID bs, fix privacy settings using user config as privacy store * feat: initial creation sets flag, rename to match libsession implementation value * fix: recipient blinded checks from open group message for blocking community requests on blinded ID version of recipient, use correct (inverted) values from before for checking polling and empty states etc * fix: pr comments for view model factory context ref, simplified user config object check for category in PrivacySettingsPreferenceFragment * fix: pr comments * fix: migrate some dependencies and functionality out of VM into repository to remove content resolver and context dependecy so tests pass again * refactor: better naming for hidesInputBar and add more tests for expected recipient view states * fix: use contact information as opposed to active conversations * fix: PR comments
This commit is contained in:
parent
f6345c86ce
commit
2466d9b4c0
@ -10,7 +10,6 @@ import androidx.annotation.DimenRes
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ViewProfilePictureBinding
|
||||
import network.loki.messenger.databinding.ViewUserBinding
|
||||
import org.session.libsession.avatars.ContactColors
|
||||
import org.session.libsession.avatars.PlaceholderAvatarPhoto
|
||||
import org.session.libsession.avatars.ProfileContactPhoto
|
||||
@ -74,7 +73,7 @@ class ProfilePictureView @JvmOverloads constructor(
|
||||
additionalDisplayName = getUserDisplayName(apk)
|
||||
}
|
||||
} else if(recipient.isOpenGroupInboxRecipient) {
|
||||
val publicKey = GroupUtil.getDecodedOpenGroupInbox(recipient.address.serialize())
|
||||
val publicKey = GroupUtil.getDecodedOpenGroupInboxSessionId(recipient.address.serialize())
|
||||
this.publicKey = publicKey
|
||||
displayName = getUserDisplayName(publicKey)
|
||||
additionalPublicKey = null
|
||||
|
@ -40,6 +40,7 @@ import androidx.annotation.DimenRes
|
||||
import androidx.core.text.set
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.drawToBitmap
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@ -78,7 +79,6 @@ import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
|
||||
import org.session.libsession.messaging.messages.visible.Reaction
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupApi.Capability
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
|
||||
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
|
||||
@ -105,13 +105,12 @@ import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.attachments.ScreenshotObserver
|
||||
import org.thoughtcrime.securesms.audio.AudioRecorder
|
||||
import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
|
||||
import org.thoughtcrime.securesms.util.SimpleTextWatcher
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener
|
||||
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.MESSAGE_TIMESTAMP
|
||||
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_DELETE
|
||||
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY
|
||||
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_RESEND
|
||||
import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_DELETE
|
||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog
|
||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.LinkPreviewDialog
|
||||
import org.thoughtcrime.securesms.conversation.v2.dialogs.SendSeedDialog
|
||||
@ -174,6 +173,7 @@ import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask
|
||||
import org.thoughtcrime.securesms.util.SimpleTextWatcher
|
||||
import org.thoughtcrime.securesms.util.isScrolledToBottom
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
import org.thoughtcrime.securesms.util.toPx
|
||||
@ -240,11 +240,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
val address = if (sessionId.prefix == IdPrefix.BLINDED && openGroup != null) {
|
||||
storage.getOrCreateBlindedIdMapping(sessionId.hexString, openGroup.server, openGroup.publicKey).sessionId?.let {
|
||||
fromSerialized(it)
|
||||
} ?: run {
|
||||
val openGroupInboxId =
|
||||
"${openGroup.server}!${openGroup.publicKey}!${sessionId.hexString}".toByteArray()
|
||||
fromSerialized(GroupUtil.getEncodedOpenGroupInboxID(openGroupInboxId))
|
||||
}
|
||||
} ?: GroupUtil.getEncodedOpenGroupInboxID(openGroup, sessionId)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
@ -253,7 +249,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
}
|
||||
} ?: finish()
|
||||
}
|
||||
viewModelFactory.create(threadId, MessagingModuleConfiguration.shared.getUserED25519KeyPair(), contentResolver)
|
||||
viewModelFactory.create(threadId, MessagingModuleConfiguration.shared.getUserED25519KeyPair())
|
||||
}
|
||||
private var actionMode: ActionMode? = null
|
||||
private var unreadCount = 0
|
||||
@ -312,8 +308,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
handleSwipeToReply(message)
|
||||
},
|
||||
onItemLongPress = { message, position, view ->
|
||||
if (!isMessageRequestThread() &&
|
||||
(viewModel.openGroup == null || Capability.REACTIONS.name.lowercase() in viewModel.serverCapabilities)
|
||||
if (!viewModel.isMessageRequestThread &&
|
||||
viewModel.canReactToMessages
|
||||
) {
|
||||
showEmojiPicker(message, view)
|
||||
} else {
|
||||
@ -596,26 +592,27 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
|
||||
// called from onCreate
|
||||
private fun setUpInputBar() {
|
||||
binding!!.inputBar.isVisible = viewModel.openGroup == null || viewModel.openGroup?.canWrite == true
|
||||
binding!!.inputBar.delegate = this
|
||||
binding!!.inputBarRecordingView.delegate = this
|
||||
val binding = binding ?: return
|
||||
binding.inputBar.isGone = viewModel.hidesInputBar()
|
||||
binding.inputBar.delegate = this
|
||||
binding.inputBarRecordingView.delegate = this
|
||||
// GIF button
|
||||
binding!!.gifButtonContainer.addView(gifButton)
|
||||
binding.gifButtonContainer.addView(gifButton)
|
||||
gifButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||
gifButton.onUp = { showGIFPicker() }
|
||||
gifButton.snIsEnabled = false
|
||||
// Document button
|
||||
binding!!.documentButtonContainer.addView(documentButton)
|
||||
binding.documentButtonContainer.addView(documentButton)
|
||||
documentButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||
documentButton.onUp = { showDocumentPicker() }
|
||||
documentButton.snIsEnabled = false
|
||||
// Library button
|
||||
binding!!.libraryButtonContainer.addView(libraryButton)
|
||||
binding.libraryButtonContainer.addView(libraryButton)
|
||||
libraryButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||
libraryButton.onUp = { pickFromLibrary() }
|
||||
libraryButton.snIsEnabled = false
|
||||
// Camera button
|
||||
binding!!.cameraButtonContainer.addView(cameraButton)
|
||||
binding.cameraButtonContainer.addView(cameraButton)
|
||||
cameraButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||
cameraButton.onUp = { showCamera() }
|
||||
cameraButton.snIsEnabled = false
|
||||
@ -764,7 +761,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
val recipient = viewModel.recipient ?: return false
|
||||
if (!isMessageRequestThread()) {
|
||||
if (!viewModel.isMessageRequestThread) {
|
||||
ConversationMenuHelper.onPrepareOptionsMenu(
|
||||
menu,
|
||||
menuInflater,
|
||||
@ -850,11 +847,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMessageRequestThread(): Boolean {
|
||||
val recipient = viewModel.recipient ?: return false
|
||||
return !recipient.isGroupRecipient && !recipient.isApproved
|
||||
}
|
||||
|
||||
private fun isOutgoingMessageRequestThread(): Boolean {
|
||||
val recipient = viewModel.recipient ?: return false
|
||||
return !recipient.isGroupRecipient &&
|
||||
@ -1069,11 +1061,13 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
private fun updatePlaceholder() {
|
||||
val recipient = viewModel.recipient
|
||||
?: return Log.w("Loki", "recipient was null in placeholder update")
|
||||
val blindedRecipient = viewModel.blindedRecipient
|
||||
val binding = binding ?: return
|
||||
val openGroup = viewModel.openGroup
|
||||
val (textResource, insertParam) = when {
|
||||
recipient.isLocalNumber -> R.string.activity_conversation_empty_state_note_to_self to null
|
||||
openGroup != null && !openGroup.canWrite -> R.string.activity_conversation_empty_state_read_only to recipient.toShortString()
|
||||
blindedRecipient?.blocksCommunityMessageRequests == true -> R.string.activity_conversation_empty_state_blocks_community_requests to recipient.toShortString()
|
||||
else -> R.string.activity_conversation_empty_state_default to recipient.toShortString()
|
||||
}
|
||||
val showPlaceholder = adapter.itemCount == 0
|
||||
|
@ -1,10 +1,8 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import android.content.ContentResolver
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.cash.copper.flow.observeQuery
|
||||
import com.goterl.lazysodium.utils.KeyPair
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
@ -21,7 +19,6 @@ import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.repository.ConversationRepository
|
||||
@ -30,7 +27,6 @@ import java.util.UUID
|
||||
class ConversationViewModel(
|
||||
val threadId: Long,
|
||||
val edKeyPair: KeyPair?,
|
||||
private val contentResolver: ContentResolver,
|
||||
private val repository: ConversationRepository,
|
||||
private val storage: Storage
|
||||
) : ViewModel() {
|
||||
@ -47,6 +43,15 @@ class ConversationViewModel(
|
||||
val recipient: Recipient?
|
||||
get() = _recipient.value
|
||||
|
||||
val blindedRecipient: Recipient?
|
||||
get() = _recipient.value?.let { recipient ->
|
||||
when {
|
||||
recipient.isOpenGroupOutboxRecipient -> recipient
|
||||
recipient.isOpenGroupInboxRecipient -> repository.maybeGetBlindedRecipient(recipient)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private var _openGroup: RetrieveOnce<OpenGroup> = RetrieveOnce {
|
||||
storage.getOpenGroup(threadId)
|
||||
}
|
||||
@ -62,12 +67,22 @@ class ConversationViewModel(
|
||||
?.let { SessionId(IdPrefix.BLINDED, it) }?.hexString
|
||||
}
|
||||
|
||||
val isMessageRequestThread : Boolean
|
||||
get() {
|
||||
val recipient = recipient ?: return false
|
||||
return !recipient.isLocalNumber && !recipient.isGroupRecipient && !recipient.isApproved
|
||||
}
|
||||
|
||||
val canReactToMessages: Boolean
|
||||
// allow reactions if the open group is null (normal conversations) or the open group's capabilities include reactions
|
||||
get() = (openGroup == null || OpenGroupApi.Capability.REACTIONS.name.lowercase() in serverCapabilities)
|
||||
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
contentResolver.observeQuery(DatabaseContentProviders.Conversation.getUriForThread(threadId))
|
||||
.collect {
|
||||
val recipientExists = storage.getRecipientForThread(threadId) != null
|
||||
if (!recipientExists && _uiState.value.conversationExists) {
|
||||
repository.recipientUpdateFlow(threadId)
|
||||
.collect { recipient ->
|
||||
if (recipient == null && _uiState.value.conversationExists) {
|
||||
_uiState.update { it.copy(conversationExists = false) }
|
||||
}
|
||||
}
|
||||
@ -199,22 +214,25 @@ class ConversationViewModel(
|
||||
_recipient.updateTo(repository.maybeGetRecipientForThreadId(threadId))
|
||||
}
|
||||
|
||||
fun hidesInputBar(): Boolean = openGroup?.canWrite != true &&
|
||||
blindedRecipient?.blocksCommunityMessageRequests == true
|
||||
|
||||
|
||||
@dagger.assisted.AssistedFactory
|
||||
interface AssistedFactory {
|
||||
fun create(threadId: Long, edKeyPair: KeyPair?, contentResolver: ContentResolver): Factory
|
||||
fun create(threadId: Long, edKeyPair: KeyPair?): Factory
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class Factory @AssistedInject constructor(
|
||||
@Assisted private val threadId: Long,
|
||||
@Assisted private val edKeyPair: KeyPair?,
|
||||
@Assisted private val contentResolver: ContentResolver,
|
||||
private val repository: ConversationRepository,
|
||||
private val storage: Storage
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ConversationViewModel(threadId, edKeyPair, contentResolver, repository, storage) as T
|
||||
return ConversationViewModel(threadId, edKeyPair, repository, storage) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,13 +63,14 @@ public class RecipientDatabase extends Database {
|
||||
private static final String FORCE_SMS_SELECTION = "force_sms_selection";
|
||||
private static final String NOTIFY_TYPE = "notify_type"; // all, mentions only, none
|
||||
private static final String WRAPPER_HASH = "wrapper_hash";
|
||||
private static final String BLOCKS_COMMUNITY_MESSAGE_REQUESTS = "blocks_community_message_requests";
|
||||
|
||||
private static final String[] RECIPIENT_PROJECTION = new String[] {
|
||||
BLOCK, APPROVED, APPROVED_ME, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED,
|
||||
PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI,
|
||||
SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL,
|
||||
UNIDENTIFIED_ACCESS_MODE,
|
||||
FORCE_SMS_SELECTION, NOTIFY_TYPE, WRAPPER_HASH
|
||||
FORCE_SMS_SELECTION, NOTIFY_TYPE, WRAPPER_HASH, BLOCKS_COMMUNITY_MESSAGE_REQUESTS
|
||||
};
|
||||
|
||||
static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
|
||||
@ -142,6 +143,11 @@ public class RecipientDatabase extends Database {
|
||||
"ADD COLUMN "+WRAPPER_HASH+" TEXT DEFAULT NULL;";
|
||||
}
|
||||
|
||||
public static String getAddBlocksCommunityMessageRequests() {
|
||||
return "ALTER TABLE "+TABLE_NAME+" "+
|
||||
"ADD COLUMN "+BLOCKS_COMMUNITY_MESSAGE_REQUESTS+" INT DEFAULT 0;";
|
||||
}
|
||||
|
||||
public static final int NOTIFY_TYPE_ALL = 0;
|
||||
public static final int NOTIFY_TYPE_MENTIONS = 1;
|
||||
public static final int NOTIFY_TYPE_NONE = 2;
|
||||
@ -197,6 +203,7 @@ public class RecipientDatabase extends Database {
|
||||
int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE));
|
||||
boolean forceSmsSelection = cursor.getInt(cursor.getColumnIndexOrThrow(FORCE_SMS_SELECTION)) == 1;
|
||||
String wrapperHash = cursor.getString(cursor.getColumnIndexOrThrow(WRAPPER_HASH));
|
||||
boolean blocksCommunityMessageRequests = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKS_COMMUNITY_MESSAGE_REQUESTS)) == 1;
|
||||
|
||||
MaterialColor color;
|
||||
byte[] profileKey = null;
|
||||
@ -228,7 +235,7 @@ public class RecipientDatabase extends Database {
|
||||
systemPhoneLabel, systemContactUri,
|
||||
signalProfileName, signalProfileAvatar, profileSharing,
|
||||
notificationChannel, Recipient.UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
|
||||
forceSmsSelection, wrapperHash));
|
||||
forceSmsSelection, wrapperHash, blocksCommunityMessageRequests));
|
||||
}
|
||||
|
||||
public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) {
|
||||
@ -395,6 +402,14 @@ public class RecipientDatabase extends Database {
|
||||
notifyRecipientListeners();
|
||||
}
|
||||
|
||||
public void setBlocksCommunityMessageRequests(@NonNull Recipient recipient, boolean isBlocked) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(BLOCKS_COMMUNITY_MESSAGE_REQUESTS, isBlocked ? 1 : 0);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.resolve().setBlocksCommunityMessageRequests(isBlocked);
|
||||
notifyRecipientListeners();
|
||||
}
|
||||
|
||||
private void updateOrInsert(Address address, ContentValues contentValues) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
|
@ -190,6 +190,11 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
db.setProfileKey(recipient, newProfileKey)
|
||||
}
|
||||
|
||||
override fun setBlocksCommunityMessageRequests(recipient: Recipient, blocksMessageRequests: Boolean) {
|
||||
val db = DatabaseComponent.get(context).recipientDatabase()
|
||||
db.setBlocksCommunityMessageRequests(recipient, blocksMessageRequests)
|
||||
}
|
||||
|
||||
override fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?) {
|
||||
val ourRecipient = fromSerialized(getUserPublicKey()!!).let {
|
||||
Recipient.from(context, it, false)
|
||||
@ -430,6 +435,10 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
return configFactory.canPerformChange(variant, publicKey, changeTimestampMs)
|
||||
}
|
||||
|
||||
override fun isCheckingCommunityRequests(): Boolean {
|
||||
return configFactory.user?.getCommunityMessageRequests() == true
|
||||
}
|
||||
|
||||
fun notifyUpdates(forConfigObject: ConfigBase) {
|
||||
when (forConfigObject) {
|
||||
is UserProfile -> updateUser(forConfigObject)
|
||||
@ -1405,7 +1414,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
val blindedId = when {
|
||||
recipient.isGroupRecipient -> null
|
||||
recipient.isOpenGroupInboxRecipient -> {
|
||||
GroupUtil.getDecodedOpenGroupInbox(address)
|
||||
GroupUtil.getDecodedOpenGroupInboxSessionId(address)
|
||||
}
|
||||
else -> {
|
||||
if (SessionId(address).prefix == IdPrefix.BLINDED) {
|
||||
@ -1524,16 +1533,12 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
|
||||
if (mapping.sessionId != null) {
|
||||
return mapping
|
||||
}
|
||||
val threadDb = DatabaseComponent.get(context).threadDatabase()
|
||||
threadDb.readerFor(threadDb.conversationList).use { reader ->
|
||||
while (reader.next != null) {
|
||||
val recipient = reader.current.recipient
|
||||
val sessionId = recipient.address.serialize()
|
||||
if (!recipient.isGroupRecipient && SodiumUtilities.sessionId(sessionId, blindedId, serverPublicKey)) {
|
||||
val contactMapping = mapping.copy(sessionId = sessionId)
|
||||
db.addBlindedIdMapping(contactMapping)
|
||||
return contactMapping
|
||||
}
|
||||
getAllContacts().forEach { contact ->
|
||||
val sessionId = SessionId(contact.sessionID)
|
||||
if (sessionId.prefix == IdPrefix.STANDARD && SodiumUtilities.sessionId(sessionId.hexString, blindedId, serverPublicKey)) {
|
||||
val contactMapping = mapping.copy(sessionId = sessionId.hexString)
|
||||
db.addBlindedIdMapping(contactMapping)
|
||||
return contactMapping
|
||||
}
|
||||
}
|
||||
db.getBlindedIdMappingsExceptFor(server).forEach {
|
||||
|
@ -88,9 +88,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int lokiV40 = 61;
|
||||
private static final int lokiV41 = 62;
|
||||
private static final int lokiV42 = 63;
|
||||
private static final int lokiV43 = 64;
|
||||
|
||||
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||
private static final int DATABASE_VERSION = lokiV42;
|
||||
private static final int DATABASE_VERSION = lokiV43;
|
||||
private static final int MIN_DATABASE_VERSION = lokiV7;
|
||||
private static final String CIPHER3_DATABASE_NAME = "signal.db";
|
||||
public static final String DATABASE_NAME = "signal_v4.db";
|
||||
@ -356,6 +357,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
executeStatements(db, ReactionDatabase.CREATE_REACTION_TRIGGERS);
|
||||
db.execSQL(RecipientDatabase.getAddWrapperHash());
|
||||
db.execSQL(RecipientDatabase.getAddBlocksCommunityMessageRequests());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -598,6 +600,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(RecipientDatabase.getAddWrapperHash());
|
||||
}
|
||||
|
||||
if (oldVersion < lokiV43) {
|
||||
db.execSQL(RecipientDatabase.getAddBlocksCommunityMessageRequests());
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
@ -0,0 +1,17 @@
|
||||
package org.thoughtcrime.securesms.dependencies
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object ContentModule {
|
||||
|
||||
@Provides
|
||||
fun providesContentResolver(@ApplicationContext context: Context) =context.contentResolver
|
||||
|
||||
}
|
@ -72,8 +72,8 @@ import org.thoughtcrime.securesms.onboarding.SeedActivity
|
||||
import org.thoughtcrime.securesms.onboarding.SeedReminderViewDelegate
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.preferences.SettingsActivity
|
||||
import org.thoughtcrime.securesms.showSessionDialog
|
||||
import org.thoughtcrime.securesms.showMuteDialog
|
||||
import org.thoughtcrime.securesms.showSessionDialog
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.IP2Country
|
||||
@ -299,12 +299,17 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
}
|
||||
EventBus.getDefault().register(this@HomeActivity)
|
||||
if (intent.hasExtra(FROM_ONBOARDING)
|
||||
&& intent.getBooleanExtra(FROM_ONBOARDING, false)
|
||||
&& !(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).areNotificationsEnabled()
|
||||
) {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.POST_NOTIFICATIONS)
|
||||
.execute()
|
||||
&& intent.getBooleanExtra(FROM_ONBOARDING, false)) {
|
||||
if ((getSystemService(NOTIFICATION_SERVICE) as NotificationManager).areNotificationsEnabled().not()) {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.POST_NOTIFICATIONS)
|
||||
.execute()
|
||||
}
|
||||
configFactory.user?.let { user ->
|
||||
if (!user.isBlockCommunityMessageRequestsSet()) {
|
||||
user.setCommunityMessageRequests(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
package org.thoughtcrime.securesms.preferences
|
||||
|
||||
import android.os.Bundle
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PrivacySettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
|
@ -8,6 +8,9 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceDataStore
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import network.loki.messenger.BuildConfig
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
@ -15,13 +18,19 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.isPasswo
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.setScreenLockEnabled
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.showSessionDialog
|
||||
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.areNotificationsEnabled
|
||||
import org.thoughtcrime.securesms.util.IntentUtils
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PrivacySettingsPreferenceFragment : ListSummaryPreferenceFragment() {
|
||||
|
||||
@Inject lateinit var configFactory: ConfigFactory
|
||||
|
||||
override fun onCreate(paramBundle: Bundle?) {
|
||||
super.onCreate(paramBundle)
|
||||
findPreference<Preference>(TextSecurePreferences.SCREEN_LOCK)!!
|
||||
@ -30,6 +39,33 @@ class PrivacySettingsPreferenceFragment : ListSummaryPreferenceFragment() {
|
||||
.onPreferenceChangeListener = TypingIndicatorsToggleListener()
|
||||
findPreference<Preference>(TextSecurePreferences.CALL_NOTIFICATIONS_ENABLED)!!
|
||||
.onPreferenceChangeListener = CallToggleListener(this) { setCall(it) }
|
||||
findPreference<PreferenceCategory>(getString(R.string.preferences__message_requests_category))?.let { category ->
|
||||
when (val user = configFactory.user) {
|
||||
null -> category.isVisible = false
|
||||
else -> SwitchPreferenceCompat(requireContext()).apply {
|
||||
key = TextSecurePreferences.ALLOW_MESSAGE_REQUESTS
|
||||
preferenceDataStore = object : PreferenceDataStore() {
|
||||
|
||||
override fun getBoolean(key: String?, defValue: Boolean): Boolean {
|
||||
if (key == TextSecurePreferences.ALLOW_MESSAGE_REQUESTS) {
|
||||
return user.getCommunityMessageRequests()
|
||||
}
|
||||
return super.getBoolean(key, defValue)
|
||||
}
|
||||
|
||||
override fun putBoolean(key: String?, value: Boolean) {
|
||||
if (key == TextSecurePreferences.ALLOW_MESSAGE_REQUESTS) {
|
||||
user.setCommunityMessageRequests(value)
|
||||
return
|
||||
}
|
||||
super.putBoolean(key, value)
|
||||
}
|
||||
}
|
||||
title = getString(R.string.preferences__message_requests_title)
|
||||
summary = getString(R.string.preferences__message_requests_summary)
|
||||
}.let(category::addPreference)
|
||||
}
|
||||
}
|
||||
initializeVisibility()
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
package org.thoughtcrime.securesms.repository
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import app.cash.copper.flow.observeQuery
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.session.libsession.database.MessageDataProvider
|
||||
import org.session.libsession.messaging.messages.Destination
|
||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||
@ -15,6 +21,7 @@ import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
||||
import org.thoughtcrime.securesms.database.DraftDatabase
|
||||
import org.thoughtcrime.securesms.database.LokiMessageDatabase
|
||||
import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
||||
@ -35,6 +42,8 @@ import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
interface ConversationRepository {
|
||||
fun maybeGetRecipientForThreadId(threadId: Long): Recipient?
|
||||
fun maybeGetBlindedRecipient(recipient: Recipient): Recipient?
|
||||
fun recipientUpdateFlow(threadId: Long): Flow<Recipient?>
|
||||
fun saveDraft(threadId: Long, text: String)
|
||||
fun getDraft(threadId: Long): String?
|
||||
fun clearDrafts(threadId: Long)
|
||||
@ -75,6 +84,7 @@ interface ConversationRepository {
|
||||
}
|
||||
|
||||
class DefaultConversationRepository @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val textSecurePreferences: TextSecurePreferences,
|
||||
private val messageDataProvider: MessageDataProvider,
|
||||
private val threadDb: ThreadDatabase,
|
||||
@ -87,13 +97,29 @@ class DefaultConversationRepository @Inject constructor(
|
||||
private val storage: Storage,
|
||||
private val lokiMessageDb: LokiMessageDatabase,
|
||||
private val sessionJobDb: SessionJobDatabase,
|
||||
private val configFactory: ConfigFactory
|
||||
private val configFactory: ConfigFactory,
|
||||
private val contentResolver: ContentResolver,
|
||||
) : ConversationRepository {
|
||||
|
||||
override fun maybeGetRecipientForThreadId(threadId: Long): Recipient? {
|
||||
return threadDb.getRecipientForThreadId(threadId)
|
||||
}
|
||||
|
||||
override fun maybeGetBlindedRecipient(recipient: Recipient): Recipient? {
|
||||
if (!recipient.isOpenGroupInboxRecipient) return null
|
||||
return Recipient.from(
|
||||
context,
|
||||
Address.fromSerialized(GroupUtil.getDecodedOpenGroupInboxSessionId(recipient.address.serialize())),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
override fun recipientUpdateFlow(threadId: Long): Flow<Recipient?> {
|
||||
return contentResolver.observeQuery(DatabaseContentProviders.Conversation.getUriForThread(threadId)).map {
|
||||
maybeGetRecipientForThreadId(threadId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveDraft(threadId: Long, text: String) {
|
||||
if (text.isEmpty()) return
|
||||
val drafts = DraftDatabase.Drafts()
|
||||
|
@ -627,6 +627,9 @@
|
||||
<string name="preferences_notifications__priority">Priority</string>
|
||||
<string name="preferences_app_protection__screenshot_notifications">Screenshot Notifications</string>
|
||||
<string name="preferences_app_protected__screenshot_notifications_summary">Receive a notification when a contact takes a screenshot of a one-to-one chat.</string>
|
||||
<string name="preferences__message_requests_category">Message Requests</string>
|
||||
<string name="preferences__message_requests_title">Community Message Requests</string>
|
||||
<string name="preferences__message_requests_summary">Allow message requests from Community conversations</string>
|
||||
<!-- **************************************** -->
|
||||
<!-- menus -->
|
||||
<!-- **************************************** -->
|
||||
@ -1033,6 +1036,7 @@
|
||||
<string name="activity_home_outdated_client_config">Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.</string>
|
||||
|
||||
<string name="activity_conversation_empty_state_read_only">There are no messages in <b>%s</b>.</string>
|
||||
<string name="activity_conversation_empty_state_blocks_community_requests"><b>%s</b> has message requests from Community conversations turned off, so you cannot send them a message.</string>
|
||||
<string name="activity_conversation_empty_state_note_to_self">You have no messages in Note to Self.</string>
|
||||
<string name="activity_conversation_empty_state_default">You have no messages from <b>%s</b>.\nSend a message to start the conversation!</string>
|
||||
|
||||
|
@ -20,6 +20,12 @@
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/preferences__message_requests_category"
|
||||
android:key="@string/preferences__message_requests_category"
|
||||
android:persistent="false">
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/preferences__read_receipts">
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
|
@ -1,42 +1,46 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import com.goterl.lazysodium.utils.KeyPair
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import org.hamcrest.CoreMatchers.endsWith
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.CoreMatchers.notNullValue
|
||||
import org.hamcrest.CoreMatchers.nullValue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.anyLong
|
||||
import org.mockito.Mockito.anySet
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.whenever
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.BaseViewModelTest
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.repository.ConversationRepository
|
||||
import org.thoughtcrime.securesms.repository.ResultOf
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
class ConversationViewModelTest: BaseViewModelTest() {
|
||||
|
||||
private val repository = mock(ConversationRepository::class.java)
|
||||
private val storage = mock(Storage::class.java)
|
||||
private val repository = mock<ConversationRepository>()
|
||||
private val storage = mock<Storage>()
|
||||
|
||||
private val threadId = 123L
|
||||
private val edKeyPair = mock(KeyPair::class.java)
|
||||
private val edKeyPair = mock<KeyPair>()
|
||||
private lateinit var recipient: Recipient
|
||||
|
||||
private val viewModel: ConversationViewModel by lazy {
|
||||
ConversationViewModel(threadId, edKeyPair, mock(), repository, storage)
|
||||
ConversationViewModel(threadId, edKeyPair, repository, storage)
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
recipient = mock(Recipient::class.java)
|
||||
recipient = mock()
|
||||
whenever(repository.maybeGetRecipientForThreadId(anyLong())).thenReturn(recipient)
|
||||
whenever(repository.recipientUpdateFlow(anyLong())).thenReturn(emptyFlow())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -79,7 +83,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
|
||||
|
||||
@Test
|
||||
fun `should delete locally`() {
|
||||
val message = mock(MessageRecord::class.java)
|
||||
val message = mock<MessageRecord>()
|
||||
|
||||
viewModel.deleteLocally(message)
|
||||
|
||||
@ -88,7 +92,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
|
||||
|
||||
@Test
|
||||
fun `should emit error message on failure to delete a message for everyone`() = runBlockingTest {
|
||||
val message = mock(MessageRecord::class.java)
|
||||
val message = mock<MessageRecord>()
|
||||
val error = Throwable()
|
||||
whenever(repository.deleteForEveryone(anyLong(), any(), any()))
|
||||
.thenReturn(ResultOf.Failure(error))
|
||||
@ -101,7 +105,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
|
||||
@Test
|
||||
fun `should emit error message on failure to delete messages without unsend request`() =
|
||||
runBlockingTest {
|
||||
val message = mock(MessageRecord::class.java)
|
||||
val message = mock<MessageRecord>()
|
||||
val error = Throwable()
|
||||
whenever(repository.deleteMessageWithoutUnsendRequest(anyLong(), anySet()))
|
||||
.thenReturn(ResultOf.Failure(error))
|
||||
@ -181,4 +185,30 @@ class ConversationViewModelTest: BaseViewModelTest() {
|
||||
assertThat(viewModel.uiState.value.uiMessages.size, equalTo(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `open group recipient should have no blinded recipient`() {
|
||||
whenever(recipient.isOpenGroupRecipient).thenReturn(true)
|
||||
whenever(recipient.isOpenGroupOutboxRecipient).thenReturn(false)
|
||||
whenever(recipient.isOpenGroupInboxRecipient).thenReturn(false)
|
||||
assertThat(viewModel.blindedRecipient, nullValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `local recipient should have input and no blinded recipient`() {
|
||||
whenever(recipient.isLocalNumber).thenReturn(true)
|
||||
assertThat(viewModel.hidesInputBar(), equalTo(false))
|
||||
assertThat(viewModel.blindedRecipient, nullValue())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `contact recipient should hide input bar if not accepting requests`() {
|
||||
whenever(recipient.isOpenGroupInboxRecipient).thenReturn(true)
|
||||
val blinded = mock<Recipient> {
|
||||
whenever(it.blocksCommunityMessageRequests).thenReturn(true)
|
||||
}
|
||||
whenever(repository.maybeGetBlindedRecipient(recipient)).thenReturn(blinded)
|
||||
assertThat(viewModel.blindedRecipient, notNullValue())
|
||||
assertThat(viewModel.hidesInputBar(), equalTo(true))
|
||||
}
|
||||
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit 7eb87028355bfc89950102c52d5b2927a25b2e22
|
||||
Subproject commit e3ccf29db08aaf0b9bb6bbe72ae5967cd183a78d
|
@ -95,4 +95,33 @@ Java_network_loki_messenger_libsession_1util_UserProfile_getNtsPriority(JNIEnv *
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
return profile->get_nts_priority();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_getCommunityMessageRequests(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
auto blinded_msg_requests = profile->get_blinded_msgreqs();
|
||||
if (blinded_msg_requests.has_value()) {
|
||||
return *blinded_msg_requests;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_setCommunityMessageRequests(
|
||||
JNIEnv *env, jobject thiz, jboolean blocks) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
profile->set_blinded_msgreqs(std::optional{(bool)blocks});
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_UserProfile_isBlockCommunityMessageRequestsSet(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
std::lock_guard lock{util::util_mutex_};
|
||||
auto profile = ptrToProfile(env, thiz);
|
||||
return profile->get_blinded_msgreqs().has_value();
|
||||
}
|
@ -126,6 +126,9 @@ class UserProfile(pointer: Long) : ConfigBase(pointer) {
|
||||
external fun setPic(userPic: UserPic)
|
||||
external fun setNtsPriority(priority: Int)
|
||||
external fun getNtsPriority(): Int
|
||||
external fun getCommunityMessageRequests(): Boolean
|
||||
external fun setCommunityMessageRequests(blocks: Boolean)
|
||||
external fun isBlockCommunityMessageRequestsSet(): Boolean
|
||||
}
|
||||
|
||||
class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {
|
||||
|
@ -42,6 +42,7 @@ interface StorageProtocol {
|
||||
fun getUserProfile(): Profile
|
||||
fun setProfileAvatar(recipient: Recipient, profileAvatar: String?)
|
||||
fun setProfilePicture(recipient: Recipient, newProfilePicture: String?, newProfileKey: ByteArray?)
|
||||
fun setBlocksCommunityMessageRequests(recipient: Recipient, blocksMessageRequests: Boolean)
|
||||
fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?)
|
||||
fun clearUserPic()
|
||||
// Signal
|
||||
@ -228,4 +229,5 @@ interface StorageProtocol {
|
||||
fun notifyConfigUpdates(forConfigObject: ConfigBase)
|
||||
fun conversationInConfig(publicKey: String?, groupPublicKey: String?, openGroupId: String?, visibleOnly: Boolean): Boolean
|
||||
fun canPerformConfigChange(variant: String, publicKey: String, changeTimestampMs: Long): Boolean
|
||||
fun isCheckingCommunityRequests(): Boolean
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ class VisibleMessage(
|
||||
var profile: Profile? = null,
|
||||
var openGroupInvitation: OpenGroupInvitation? = null,
|
||||
var reaction: Reaction? = null,
|
||||
var hasMention: Boolean = false
|
||||
var hasMention: Boolean = false,
|
||||
var blocksMessageRequests: Boolean = false
|
||||
) : Message() {
|
||||
|
||||
override val isSelfSendValid: Boolean = true
|
||||
@ -74,6 +75,9 @@ class VisibleMessage(
|
||||
val reaction = Reaction.fromProto(reactionProto)
|
||||
result.reaction = reaction
|
||||
}
|
||||
|
||||
result.blocksMessageRequests = with (dataMessage) { hasBlocksCommunityMessageRequests() && blocksCommunityMessageRequests }
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -141,6 +145,8 @@ class VisibleMessage(
|
||||
return null
|
||||
}
|
||||
}
|
||||
// Community blocked message requests flag
|
||||
dataMessage.blocksCommunityMessageRequests = blocksMessageRequests
|
||||
// Sync target
|
||||
if (syncTarget != null) {
|
||||
dataMessage.syncTarget = syncTarget
|
||||
|
@ -753,7 +753,8 @@ object OpenGroupApi {
|
||||
)
|
||||
}
|
||||
val serverCapabilities = storage.getServerCapabilities(server)
|
||||
if (serverCapabilities.contains(Capability.BLIND.name.lowercase())) {
|
||||
val isAcceptingCommunityRequests = storage.isCheckingCommunityRequests()
|
||||
if (serverCapabilities.contains(Capability.BLIND.name.lowercase()) && isAcceptingCommunityRequests) {
|
||||
requests.add(
|
||||
if (lastInboxMessageId == null) {
|
||||
BatchRequestInfo(
|
||||
|
@ -242,9 +242,16 @@ object MessageSender {
|
||||
private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
|
||||
val deferred = deferred<Unit, Exception>()
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val configFactory = MessagingModuleConfiguration.shared.configFactory
|
||||
if (message.sentTimestamp == null) {
|
||||
message.sentTimestamp = SnodeAPI.nowWithOffset
|
||||
}
|
||||
// Attach the blocks message requests info
|
||||
configFactory.user?.let { user ->
|
||||
if (message is VisibleMessage) {
|
||||
message.blocksMessageRequests = !user.getCommunityMessageRequests()
|
||||
}
|
||||
}
|
||||
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()!!
|
||||
var serverCapabilities = listOf<String>()
|
||||
var blindedPublicKey: ByteArray? = null
|
||||
|
@ -304,6 +304,10 @@ fun MessageReceiver.handleVisibleMessage(
|
||||
profileManager.setProfilePicture(context, recipient, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
if (userPublicKey != messageSender && !isUserBlindedSender) {
|
||||
storage.setBlocksCommunityMessageRequests(recipient, message.blocksMessageRequests)
|
||||
}
|
||||
}
|
||||
// Parse quote if needed
|
||||
var quoteModel: QuoteModel? = null
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
import network.loki.messenger.libsession_util.util.GroupInfo
|
||||
import org.session.libsession.messaging.open_groups.OpenGroup
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsignal.messages.SignalServiceGroup
|
||||
import org.session.libsignal.utilities.Hex
|
||||
import java.io.IOException
|
||||
@ -16,8 +17,15 @@ object GroupUtil {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupInboxID(groupInboxID: ByteArray): String {
|
||||
return OPEN_GROUP_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID)
|
||||
fun getEncodedOpenGroupInboxID(openGroup: OpenGroup, sessionId: SessionId): Address {
|
||||
val openGroupInboxId =
|
||||
"${openGroup.server}!${openGroup.publicKey}!${sessionId.hexString}".toByteArray()
|
||||
return getEncodedOpenGroupInboxID(openGroupInboxId)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEncodedOpenGroupInboxID(groupInboxID: ByteArray): Address {
|
||||
return Address.fromSerialized(OPEN_GROUP_INBOX_PREFIX + Hex.toStringCondensed(groupInboxID))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -52,7 +60,7 @@ object GroupUtil {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDecodedOpenGroupInbox(groupID: String): String {
|
||||
fun getDecodedOpenGroupInboxSessionId(groupID: String): String {
|
||||
val decodedGroupId = getDecodedGroupID(groupID)
|
||||
if (decodedGroupId.split("!").count() > 2) {
|
||||
return decodedGroupId.split("!", limit = 3)[2]
|
||||
|
@ -287,6 +287,8 @@ interface TextSecurePreferences {
|
||||
const val OCEAN_DARK = "ocean.dark"
|
||||
const val OCEAN_LIGHT = "ocean.light"
|
||||
|
||||
const val ALLOW_MESSAGE_REQUESTS = "libsession.ALLOW_MESSAGE_REQUESTS"
|
||||
|
||||
@JvmStatic
|
||||
fun getLastConfigurationSyncTime(context: Context): Long {
|
||||
return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0)
|
||||
|
@ -100,6 +100,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
private String notificationChannel;
|
||||
private boolean forceSmsSelection;
|
||||
private String wrapperHash;
|
||||
private boolean blocksCommunityMessageRequests;
|
||||
|
||||
private @NonNull UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.ENABLED;
|
||||
|
||||
@ -192,6 +193,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
this.unidentifiedAccessMode = details.get().unidentifiedAccessMode;
|
||||
this.forceSmsSelection = details.get().forceSmsSelection;
|
||||
this.notifyType = details.get().notifyType;
|
||||
this.blocksCommunityMessageRequests = details.get().blocksCommunityMessageRequests;
|
||||
|
||||
this.participants.clear();
|
||||
this.participants.addAll(details.get().participants);
|
||||
@ -228,6 +230,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
Recipient.this.unidentifiedAccessMode = result.unidentifiedAccessMode;
|
||||
Recipient.this.forceSmsSelection = result.forceSmsSelection;
|
||||
Recipient.this.notifyType = result.notifyType;
|
||||
Recipient.this.blocksCommunityMessageRequests = result.blocksCommunityMessageRequests;
|
||||
|
||||
Recipient.this.participants.clear();
|
||||
Recipient.this.participants.addAll(result.participants);
|
||||
@ -281,6 +284,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
this.unidentifiedAccessMode = details.unidentifiedAccessMode;
|
||||
this.forceSmsSelection = details.forceSmsSelection;
|
||||
this.wrapperHash = details.wrapperHash;
|
||||
this.blocksCommunityMessageRequests = details.blocksCommunityMessageRequests;
|
||||
|
||||
this.participants.addAll(details.participants);
|
||||
this.resolving = false;
|
||||
@ -321,7 +325,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
return this.name;
|
||||
}
|
||||
} else if (isOpenGroupInboxRecipient()){
|
||||
String inboxID = GroupUtil.getDecodedOpenGroupInbox(sessionID);
|
||||
String inboxID = GroupUtil.getDecodedOpenGroupInboxSessionId(sessionID);
|
||||
Contact contact = storage.getContactWithSessionID(inboxID);
|
||||
if (contact == null) { return sessionID; }
|
||||
return contact.displayName(Contact.ContactContext.REGULAR);
|
||||
@ -345,6 +349,18 @@ public class Recipient implements RecipientModifiedListener {
|
||||
if (notify) notifyListeners();
|
||||
}
|
||||
|
||||
public boolean getBlocksCommunityMessageRequests() {
|
||||
return blocksCommunityMessageRequests;
|
||||
}
|
||||
|
||||
public void setBlocksCommunityMessageRequests(boolean blocksCommunityMessageRequests) {
|
||||
synchronized (this) {
|
||||
this.blocksCommunityMessageRequests = blocksCommunityMessageRequests;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public synchronized @NonNull MaterialColor getColor() {
|
||||
if (isGroupRecipient()) return MaterialColor.GROUP;
|
||||
else if (color != null) return color;
|
||||
@ -759,12 +775,43 @@ public class Recipient implements RecipientModifiedListener {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Recipient recipient = (Recipient) o;
|
||||
return resolving == recipient.resolving && mutedUntil == recipient.mutedUntil && notifyType == recipient.notifyType && blocked == recipient.blocked && approved == recipient.approved && approvedMe == recipient.approvedMe && expireMessages == recipient.expireMessages && address.equals(recipient.address) && Objects.equals(name, recipient.name) && Objects.equals(customLabel, recipient.customLabel) && Objects.equals(groupAvatarId, recipient.groupAvatarId) && Arrays.equals(profileKey, recipient.profileKey) && Objects.equals(profileName, recipient.profileName) && Objects.equals(profileAvatar, recipient.profileAvatar) && Objects.equals(wrapperHash, recipient.wrapperHash);
|
||||
return resolving == recipient.resolving
|
||||
&& mutedUntil == recipient.mutedUntil
|
||||
&& notifyType == recipient.notifyType
|
||||
&& blocked == recipient.blocked
|
||||
&& approved == recipient.approved
|
||||
&& approvedMe == recipient.approvedMe
|
||||
&& expireMessages == recipient.expireMessages
|
||||
&& address.equals(recipient.address)
|
||||
&& Objects.equals(name, recipient.name)
|
||||
&& Objects.equals(customLabel, recipient.customLabel)
|
||||
&& Objects.equals(groupAvatarId, recipient.groupAvatarId)
|
||||
&& Arrays.equals(profileKey, recipient.profileKey)
|
||||
&& Objects.equals(profileName, recipient.profileName)
|
||||
&& Objects.equals(profileAvatar, recipient.profileAvatar)
|
||||
&& Objects.equals(wrapperHash, recipient.wrapperHash)
|
||||
&& blocksCommunityMessageRequests == recipient.blocksCommunityMessageRequests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(address, name, customLabel, resolving, groupAvatarId, mutedUntil, notifyType, blocked, approved, approvedMe, expireMessages, profileName, profileAvatar, wrapperHash);
|
||||
int result = Objects.hash(
|
||||
address,
|
||||
name,
|
||||
customLabel,
|
||||
resolving,
|
||||
groupAvatarId,
|
||||
mutedUntil,
|
||||
notifyType,
|
||||
blocked,
|
||||
approved,
|
||||
approvedMe,
|
||||
expireMessages,
|
||||
profileName,
|
||||
profileAvatar,
|
||||
wrapperHash,
|
||||
blocksCommunityMessageRequests
|
||||
);
|
||||
result = 31 * result + Arrays.hashCode(profileKey);
|
||||
return result;
|
||||
}
|
||||
@ -869,55 +916,59 @@ public class Recipient implements RecipientModifiedListener {
|
||||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
private final boolean forceSmsSelection;
|
||||
private final String wrapperHash;
|
||||
private final boolean blocksCommunityMessageRequests;
|
||||
|
||||
public RecipientSettings(boolean blocked, boolean approved, boolean approvedMe, long muteUntil,
|
||||
int notifyType,
|
||||
@NonNull VibrateState messageVibrateState,
|
||||
@NonNull VibrateState callVibrateState,
|
||||
@Nullable Uri messageRingtone,
|
||||
@Nullable Uri callRingtone,
|
||||
@Nullable MaterialColor color,
|
||||
int defaultSubscriptionId,
|
||||
int expireMessages,
|
||||
@NonNull RegisteredState registered,
|
||||
@Nullable byte[] profileKey,
|
||||
@Nullable String systemDisplayName,
|
||||
@Nullable String systemContactPhoto,
|
||||
@Nullable String systemPhoneLabel,
|
||||
@Nullable String systemContactUri,
|
||||
@Nullable String signalProfileName,
|
||||
@Nullable String signalProfileAvatar,
|
||||
boolean profileSharing,
|
||||
@Nullable String notificationChannel,
|
||||
@NonNull UnidentifiedAccessMode unidentifiedAccessMode,
|
||||
boolean forceSmsSelection,
|
||||
String wrapperHash)
|
||||
int notifyType,
|
||||
@NonNull VibrateState messageVibrateState,
|
||||
@NonNull VibrateState callVibrateState,
|
||||
@Nullable Uri messageRingtone,
|
||||
@Nullable Uri callRingtone,
|
||||
@Nullable MaterialColor color,
|
||||
int defaultSubscriptionId,
|
||||
int expireMessages,
|
||||
@NonNull RegisteredState registered,
|
||||
@Nullable byte[] profileKey,
|
||||
@Nullable String systemDisplayName,
|
||||
@Nullable String systemContactPhoto,
|
||||
@Nullable String systemPhoneLabel,
|
||||
@Nullable String systemContactUri,
|
||||
@Nullable String signalProfileName,
|
||||
@Nullable String signalProfileAvatar,
|
||||
boolean profileSharing,
|
||||
@Nullable String notificationChannel,
|
||||
@NonNull UnidentifiedAccessMode unidentifiedAccessMode,
|
||||
boolean forceSmsSelection,
|
||||
String wrapperHash,
|
||||
boolean blocksCommunityMessageRequests
|
||||
)
|
||||
{
|
||||
this.blocked = blocked;
|
||||
this.approved = approved;
|
||||
this.approvedMe = approvedMe;
|
||||
this.muteUntil = muteUntil;
|
||||
this.notifyType = notifyType;
|
||||
this.messageVibrateState = messageVibrateState;
|
||||
this.callVibrateState = callVibrateState;
|
||||
this.messageRingtone = messageRingtone;
|
||||
this.callRingtone = callRingtone;
|
||||
this.color = color;
|
||||
this.defaultSubscriptionId = defaultSubscriptionId;
|
||||
this.expireMessages = expireMessages;
|
||||
this.registered = registered;
|
||||
this.profileKey = profileKey;
|
||||
this.systemDisplayName = systemDisplayName;
|
||||
this.systemContactPhoto = systemContactPhoto;
|
||||
this.systemPhoneLabel = systemPhoneLabel;
|
||||
this.systemContactUri = systemContactUri;
|
||||
this.signalProfileName = signalProfileName;
|
||||
this.signalProfileAvatar = signalProfileAvatar;
|
||||
this.profileSharing = profileSharing;
|
||||
this.notificationChannel = notificationChannel;
|
||||
this.unidentifiedAccessMode = unidentifiedAccessMode;
|
||||
this.forceSmsSelection = forceSmsSelection;
|
||||
this.wrapperHash = wrapperHash;
|
||||
this.blocked = blocked;
|
||||
this.approved = approved;
|
||||
this.approvedMe = approvedMe;
|
||||
this.muteUntil = muteUntil;
|
||||
this.notifyType = notifyType;
|
||||
this.messageVibrateState = messageVibrateState;
|
||||
this.callVibrateState = callVibrateState;
|
||||
this.messageRingtone = messageRingtone;
|
||||
this.callRingtone = callRingtone;
|
||||
this.color = color;
|
||||
this.defaultSubscriptionId = defaultSubscriptionId;
|
||||
this.expireMessages = expireMessages;
|
||||
this.registered = registered;
|
||||
this.profileKey = profileKey;
|
||||
this.systemDisplayName = systemDisplayName;
|
||||
this.systemContactPhoto = systemContactPhoto;
|
||||
this.systemPhoneLabel = systemPhoneLabel;
|
||||
this.systemContactUri = systemContactUri;
|
||||
this.signalProfileName = signalProfileName;
|
||||
this.signalProfileAvatar = signalProfileAvatar;
|
||||
this.profileSharing = profileSharing;
|
||||
this.notificationChannel = notificationChannel;
|
||||
this.unidentifiedAccessMode = unidentifiedAccessMode;
|
||||
this.forceSmsSelection = forceSmsSelection;
|
||||
this.wrapperHash = wrapperHash;
|
||||
this.blocksCommunityMessageRequests = blocksCommunityMessageRequests;
|
||||
}
|
||||
|
||||
public @Nullable MaterialColor getColor() {
|
||||
@ -1020,6 +1071,10 @@ public class Recipient implements RecipientModifiedListener {
|
||||
return wrapperHash;
|
||||
}
|
||||
|
||||
public boolean getBlocksCommunityMessageRequests() {
|
||||
return blocksCommunityMessageRequests;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -178,6 +178,7 @@ class RecipientProvider {
|
||||
@NonNull final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
final boolean forceSmsSelection;
|
||||
final String wrapperHash;
|
||||
final boolean blocksCommunityMessageRequests;
|
||||
|
||||
RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId,
|
||||
boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings,
|
||||
@ -211,6 +212,7 @@ class RecipientProvider {
|
||||
this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED;
|
||||
this.forceSmsSelection = settings != null && settings.isForceSmsSelection();
|
||||
this.wrapperHash = settings != null ? settings.getWrapperHash() : null;
|
||||
this.blocksCommunityMessageRequests = settings != null && settings.getBlocksCommunityMessageRequests();
|
||||
|
||||
if (name == null && settings != null) this.name = settings.getSystemDisplayName();
|
||||
else this.name = name;
|
||||
|
@ -163,20 +163,21 @@ message DataMessage {
|
||||
required Action action = 4;
|
||||
}
|
||||
|
||||
optional string body = 1;
|
||||
repeated AttachmentPointer attachments = 2;
|
||||
optional GroupContext group = 3;
|
||||
optional uint32 flags = 4;
|
||||
optional uint32 expireTimer = 5;
|
||||
optional bytes profileKey = 6;
|
||||
optional uint64 timestamp = 7;
|
||||
optional Quote quote = 8;
|
||||
repeated Preview preview = 10;
|
||||
optional Reaction reaction = 11;
|
||||
optional LokiProfile profile = 101;
|
||||
optional OpenGroupInvitation openGroupInvitation = 102;
|
||||
optional ClosedGroupControlMessage closedGroupControlMessage = 104;
|
||||
optional string syncTarget = 105;
|
||||
optional string body = 1;
|
||||
repeated AttachmentPointer attachments = 2;
|
||||
optional GroupContext group = 3;
|
||||
optional uint32 flags = 4;
|
||||
optional uint32 expireTimer = 5;
|
||||
optional bytes profileKey = 6;
|
||||
optional uint64 timestamp = 7;
|
||||
optional Quote quote = 8;
|
||||
repeated Preview preview = 10;
|
||||
optional Reaction reaction = 11;
|
||||
optional LokiProfile profile = 101;
|
||||
optional OpenGroupInvitation openGroupInvitation = 102;
|
||||
optional ClosedGroupControlMessage closedGroupControlMessage = 104;
|
||||
optional string syncTarget = 105;
|
||||
optional bool blocksCommunityMessageRequests = 106;
|
||||
}
|
||||
|
||||
message CallMessage {
|
||||
|
@ -5890,6 +5890,16 @@ public final class SignalServiceProtos {
|
||||
*/
|
||||
com.google.protobuf.ByteString
|
||||
getSyncTargetBytes();
|
||||
|
||||
// optional bool blocksCommunityMessageRequests = 106;
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
boolean hasBlocksCommunityMessageRequests();
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
boolean getBlocksCommunityMessageRequests();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code signalservice.DataMessage}
|
||||
@ -6066,6 +6076,11 @@ public final class SignalServiceProtos {
|
||||
syncTarget_ = input.readBytes();
|
||||
break;
|
||||
}
|
||||
case 848: {
|
||||
bitField0_ |= 0x00001000;
|
||||
blocksCommunityMessageRequests_ = input.readBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
@ -14336,6 +14351,22 @@ public final class SignalServiceProtos {
|
||||
}
|
||||
}
|
||||
|
||||
// optional bool blocksCommunityMessageRequests = 106;
|
||||
public static final int BLOCKSCOMMUNITYMESSAGEREQUESTS_FIELD_NUMBER = 106;
|
||||
private boolean blocksCommunityMessageRequests_;
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
public boolean hasBlocksCommunityMessageRequests() {
|
||||
return ((bitField0_ & 0x00001000) == 0x00001000);
|
||||
}
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
public boolean getBlocksCommunityMessageRequests() {
|
||||
return blocksCommunityMessageRequests_;
|
||||
}
|
||||
|
||||
private void initFields() {
|
||||
body_ = "";
|
||||
attachments_ = java.util.Collections.emptyList();
|
||||
@ -14351,6 +14382,7 @@ public final class SignalServiceProtos {
|
||||
openGroupInvitation_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance();
|
||||
closedGroupControlMessage_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance();
|
||||
syncTarget_ = "";
|
||||
blocksCommunityMessageRequests_ = false;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
public final boolean isInitialized() {
|
||||
@ -14448,6 +14480,9 @@ public final class SignalServiceProtos {
|
||||
if (((bitField0_ & 0x00000800) == 0x00000800)) {
|
||||
output.writeBytes(105, getSyncTargetBytes());
|
||||
}
|
||||
if (((bitField0_ & 0x00001000) == 0x00001000)) {
|
||||
output.writeBool(106, blocksCommunityMessageRequests_);
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
@ -14513,6 +14548,10 @@ public final class SignalServiceProtos {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(105, getSyncTargetBytes());
|
||||
}
|
||||
if (((bitField0_ & 0x00001000) == 0x00001000)) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBoolSize(106, blocksCommunityMessageRequests_);
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@ -14697,6 +14736,8 @@ public final class SignalServiceProtos {
|
||||
bitField0_ = (bitField0_ & ~0x00001000);
|
||||
syncTarget_ = "";
|
||||
bitField0_ = (bitField0_ & ~0x00002000);
|
||||
blocksCommunityMessageRequests_ = false;
|
||||
bitField0_ = (bitField0_ & ~0x00004000);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -14815,6 +14856,10 @@ public final class SignalServiceProtos {
|
||||
to_bitField0_ |= 0x00000800;
|
||||
}
|
||||
result.syncTarget_ = syncTarget_;
|
||||
if (((from_bitField0_ & 0x00004000) == 0x00004000)) {
|
||||
to_bitField0_ |= 0x00001000;
|
||||
}
|
||||
result.blocksCommunityMessageRequests_ = blocksCommunityMessageRequests_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
onBuilt();
|
||||
return result;
|
||||
@ -14923,6 +14968,9 @@ public final class SignalServiceProtos {
|
||||
syncTarget_ = other.syncTarget_;
|
||||
onChanged();
|
||||
}
|
||||
if (other.hasBlocksCommunityMessageRequests()) {
|
||||
setBlocksCommunityMessageRequests(other.getBlocksCommunityMessageRequests());
|
||||
}
|
||||
this.mergeUnknownFields(other.getUnknownFields());
|
||||
return this;
|
||||
}
|
||||
@ -16457,6 +16505,39 @@ public final class SignalServiceProtos {
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional bool blocksCommunityMessageRequests = 106;
|
||||
private boolean blocksCommunityMessageRequests_ ;
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
public boolean hasBlocksCommunityMessageRequests() {
|
||||
return ((bitField0_ & 0x00004000) == 0x00004000);
|
||||
}
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
public boolean getBlocksCommunityMessageRequests() {
|
||||
return blocksCommunityMessageRequests_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
public Builder setBlocksCommunityMessageRequests(boolean value) {
|
||||
bitField0_ |= 0x00004000;
|
||||
blocksCommunityMessageRequests_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bool blocksCommunityMessageRequests = 106;</code>
|
||||
*/
|
||||
public Builder clearBlocksCommunityMessageRequests() {
|
||||
bitField0_ = (bitField0_ & ~0x00004000);
|
||||
blocksCommunityMessageRequests_ = false;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:signalservice.DataMessage)
|
||||
}
|
||||
|
||||
@ -27160,7 +27241,7 @@ public final class SignalServiceProtos {
|
||||
"actionNotification\022<\n\004type\030\001 \002(\0162..signa" +
|
||||
"lservice.DataExtractionNotification.Type" +
|
||||
"\022\021\n\ttimestamp\030\002 \001(\004\"\'\n\004Type\022\016\n\nSCREENSHO" +
|
||||
"T\020\001\022\017\n\013MEDIA_SAVED\020\002\"\361\r\n\013DataMessage\022\014\n\004",
|
||||
"T\020\001\022\017\n\013MEDIA_SAVED\020\002\"\231\016\n\013DataMessage\022\014\n\004",
|
||||
"body\030\001 \001(\t\0225\n\013attachments\030\002 \003(\0132 .signal" +
|
||||
"service.AttachmentPointer\022*\n\005group\030\003 \001(\013" +
|
||||
"2\033.signalservice.GroupContext\022\r\n\005flags\030\004" +
|
||||
@ -27175,12 +27256,13 @@ public final class SignalServiceProtos {
|
||||
"ice.DataMessage.OpenGroupInvitation\022W\n\031c" +
|
||||
"losedGroupControlMessage\030h \001(\01324.signals" +
|
||||
"ervice.DataMessage.ClosedGroupControlMes" +
|
||||
"sage\022\022\n\nsyncTarget\030i \001(\t\032\225\002\n\005Quote\022\n\n\002id" +
|
||||
"sage\022\022\n\nsyncTarget\030i \001(\t\022&\n\036blocksCommun" +
|
||||
"ityMessageRequests\030j \001(\010\032\225\002\n\005Quote\022\n\n\002id" +
|
||||
"\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\014\n\004text\030\003 \001(\t\022F\n\013" +
|
||||
"attachments\030\004 \003(\01321.signalservice.DataMe" +
|
||||
"ssage.Quote.QuotedAttachment\032\231\001\n\020QuotedA" +
|
||||
"ttachment\022\023\n\013contentType\030\001 \001(\t\022\020\n\010fileNa" +
|
||||
"me\030\002 \001(\t\0223\n\tthumbnail\030\003 \001(\0132 .signalserv",
|
||||
"ttachment\022\023\n\013contentType\030\001 \001(\t\022\020\n\010fileNa",
|
||||
"me\030\002 \001(\t\0223\n\tthumbnail\030\003 \001(\0132 .signalserv" +
|
||||
"ice.AttachmentPointer\022\r\n\005flags\030\004 \001(\r\"\032\n\005" +
|
||||
"Flags\022\021\n\rVOICE_MESSAGE\020\001\032V\n\007Preview\022\013\n\003u" +
|
||||
"rl\030\001 \002(\t\022\r\n\005title\030\002 \001(\t\022/\n\005image\030\003 \001(\0132 " +
|
||||
@ -27189,8 +27271,8 @@ public final class SignalServiceProtos {
|
||||
"icture\030\002 \001(\t\0320\n\023OpenGroupInvitation\022\013\n\003u" +
|
||||
"rl\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\374\003\n\031ClosedGroupCo" +
|
||||
"ntrolMessage\022G\n\004type\030\001 \002(\01629.signalservi" +
|
||||
"ce.DataMessage.ClosedGroupControlMessage" +
|
||||
".Type\022\021\n\tpublicKey\030\002 \001(\014\022\014\n\004name\030\003 \001(\t\0221",
|
||||
"ce.DataMessage.ClosedGroupControlMessage",
|
||||
".Type\022\021\n\tpublicKey\030\002 \001(\014\022\014\n\004name\030\003 \001(\t\0221" +
|
||||
"\n\021encryptionKeyPair\030\004 \001(\0132\026.signalservic" +
|
||||
"e.KeyPair\022\017\n\007members\030\005 \003(\014\022\016\n\006admins\030\006 \003" +
|
||||
"(\014\022U\n\010wrappers\030\007 \003(\0132C.signalservice.Dat" +
|
||||
@ -27199,8 +27281,8 @@ public final class SignalServiceProtos {
|
||||
"yPairWrapper\022\021\n\tpublicKey\030\001 \002(\014\022\030\n\020encry" +
|
||||
"ptedKeyPair\030\002 \002(\014\"r\n\004Type\022\007\n\003NEW\020\001\022\027\n\023EN" +
|
||||
"CRYPTION_KEY_PAIR\020\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\r" +
|
||||
"MEMBERS_ADDED\020\005\022\023\n\017MEMBERS_REMOVED\020\006\022\017\n\013" +
|
||||
"MEMBER_LEFT\020\007\032\222\001\n\010Reaction\022\n\n\002id\030\001 \002(\004\022\016",
|
||||
"MEMBERS_ADDED\020\005\022\023\n\017MEMBERS_REMOVED\020\006\022\017\n\013",
|
||||
"MEMBER_LEFT\020\007\032\222\001\n\010Reaction\022\n\n\002id\030\001 \002(\004\022\016" +
|
||||
"\n\006author\030\002 \002(\t\022\r\n\005emoji\030\003 \001(\t\022:\n\006action\030" +
|
||||
"\004 \002(\0162*.signalservice.DataMessage.Reacti" +
|
||||
"on.Action\"\037\n\006Action\022\t\n\005REACT\020\000\022\n\n\006REMOVE" +
|
||||
@ -27209,8 +27291,8 @@ public final class SignalServiceProtos {
|
||||
"ervice.CallMessage.Type\022\014\n\004sdps\030\002 \003(\t\022\027\n" +
|
||||
"\017sdpMLineIndexes\030\003 \003(\r\022\017\n\007sdpMids\030\004 \003(\t\022" +
|
||||
"\014\n\004uuid\030\005 \002(\t\"f\n\004Type\022\r\n\tPRE_OFFER\020\006\022\t\n\005" +
|
||||
"OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWE" +
|
||||
"R\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004",
|
||||
"OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWE",
|
||||
"R\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004" +
|
||||
"\n\024ConfigurationMessage\022E\n\014closedGroups\030\001" +
|
||||
" \003(\0132/.signalservice.ConfigurationMessag" +
|
||||
"e.ClosedGroup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013dis" +
|
||||
@ -27219,8 +27301,8 @@ public final class SignalServiceProtos {
|
||||
"ignalservice.ConfigurationMessage.Contac" +
|
||||
"t\032\233\001\n\013ClosedGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004" +
|
||||
"name\030\002 \001(\t\0221\n\021encryptionKeyPair\030\003 \001(\0132\026." +
|
||||
"signalservice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016" +
|
||||
"\n\006admins\030\005 \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032",
|
||||
"signalservice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016",
|
||||
"\n\006admins\030\005 \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032" +
|
||||
"\223\001\n\007Contact\022\021\n\tpublicKey\030\001 \002(\014\022\014\n\004name\030\002" +
|
||||
" \002(\t\022\026\n\016profilePicture\030\003 \001(\t\022\022\n\nprofileK" +
|
||||
"ey\030\004 \001(\014\022\022\n\nisApproved\030\005 \001(\010\022\021\n\tisBlocke" +
|
||||
@ -27229,8 +27311,8 @@ public final class SignalServiceProtos {
|
||||
"rofileKey\030\002 \001(\014\0227\n\007profile\030\003 \001(\0132&.signa" +
|
||||
"lservice.DataMessage.LokiProfile\"\375\001\n\023Sha" +
|
||||
"redConfigMessage\0225\n\004kind\030\001 \002(\0162\'.signals" +
|
||||
"ervice.SharedConfigMessage.Kind\022\r\n\005seqno" +
|
||||
"\030\002 \002(\003\022\014\n\004data\030\003 \002(\014\"\221\001\n\004Kind\022\020\n\014USER_PR",
|
||||
"ervice.SharedConfigMessage.Kind\022\r\n\005seqno",
|
||||
"\030\002 \002(\003\022\014\n\004data\030\003 \002(\014\"\221\001\n\004Kind\022\020\n\014USER_PR" +
|
||||
"OFILE\020\001\022\014\n\010CONTACTS\020\002\022\027\n\023CONVO_INFO_VOLA" +
|
||||
"TILE\020\003\022\n\n\006GROUPS\020\004\022\025\n\021CLOSED_GROUP_INFO\020" +
|
||||
"\005\022\030\n\024CLOSED_GROUP_MEMBERS\020\006\022\023\n\017ENCRYPTIO" +
|
||||
@ -27239,8 +27321,8 @@ public final class SignalServiceProtos {
|
||||
"timestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022\010\n" +
|
||||
"\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 \002(" +
|
||||
"\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004s" +
|
||||
"ize\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest\030\006" +
|
||||
" \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n",
|
||||
"ize\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest\030\006",
|
||||
" \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n" +
|
||||
"\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007caption\030" +
|
||||
"\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MES" +
|
||||
"SAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n\004t" +
|
||||
@ -27249,7 +27331,7 @@ public final class SignalServiceProtos {
|
||||
"atar\030\005 \001(\0132 .signalservice.AttachmentPoi" +
|
||||
"nter\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020" +
|
||||
"\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014" +
|
||||
"REQUEST_INFO\020\004B3\n\034org.session.libsignal." +
|
||||
"REQUEST_INFO\020\004B3\n\034org.session.libsignal.",
|
||||
"protosB\023SignalServiceProtos"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
@ -27298,7 +27380,7 @@ public final class SignalServiceProtos {
|
||||
internal_static_signalservice_DataMessage_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_signalservice_DataMessage_descriptor,
|
||||
new java.lang.String[] { "Body", "Attachments", "Group", "Flags", "ExpireTimer", "ProfileKey", "Timestamp", "Quote", "Preview", "Reaction", "Profile", "OpenGroupInvitation", "ClosedGroupControlMessage", "SyncTarget", });
|
||||
new java.lang.String[] { "Body", "Attachments", "Group", "Flags", "ExpireTimer", "ProfileKey", "Timestamp", "Quote", "Preview", "Reaction", "Profile", "OpenGroupInvitation", "ClosedGroupControlMessage", "SyncTarget", "BlocksCommunityMessageRequests", });
|
||||
internal_static_signalservice_DataMessage_Quote_descriptor =
|
||||
internal_static_signalservice_DataMessage_descriptor.getNestedTypes().get(0);
|
||||
internal_static_signalservice_DataMessage_Quote_fieldAccessorTable = new
|
||||
|
Loading…
Reference in New Issue
Block a user