mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-29 12:18:33 +00:00
Merge branch 'master' into calls
# Conflicts: # app/build.gradle # app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt # app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt # app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt # app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java # app/src/main/res/values/strings.xml # app/src/main/res/values/styles.xml # libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt # libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiver.kt # libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt # libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java
This commit is contained in:
@@ -46,6 +46,11 @@ public class AvatarHelper {
|
||||
return new File(avatarDirectory, new File(address.serialize()).getName());
|
||||
}
|
||||
|
||||
public static boolean avatarFileExists(@NonNull Context context , @NonNull Address address) {
|
||||
File avatarFile = getAvatarFile(context, address);
|
||||
return avatarFile.exists();
|
||||
}
|
||||
|
||||
public static void setAvatar(@NonNull Context context, @NonNull Address address, @Nullable byte[] data)
|
||||
throws IOException
|
||||
{
|
||||
|
||||
@@ -5,10 +5,10 @@ import android.net.Uri
|
||||
import org.session.libsession.messaging.calls.CallMessageType
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||
import org.session.libsession.messaging.jobs.GroupAvatarDownloadJob
|
||||
import org.session.libsession.messaging.jobs.Job
|
||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||
import org.session.libsession.messaging.messages.visible.Attachment
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupV2
|
||||
@@ -157,6 +157,9 @@ interface StorageProtocol {
|
||||
*/
|
||||
fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long?
|
||||
fun insertDataExtractionNotificationMessage(senderPublicKey: String, message: DataExtractionNotificationInfoMessage, sentTimestamp: Long)
|
||||
fun insertMessageRequestResponse(response: MessageRequestResponse)
|
||||
fun setRecipientApproved(recipient: Recipient, approved: Boolean)
|
||||
fun setRecipientApprovedMe(recipient: Recipient, approvedMe: Boolean)
|
||||
fun insertCallMessage(senderPublicKey: String, callMessageType: CallMessageType, sentTimestamp: Long)
|
||||
fun conversationHasOutgoing(userPublicKey: String): Boolean
|
||||
}
|
||||
|
||||
@@ -60,19 +60,22 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
||||
}
|
||||
}
|
||||
|
||||
class Contact(var publicKey: String, var name: String, var profilePicture: String?, var profileKey: ByteArray?) {
|
||||
class Contact(var publicKey: String, var name: String, var profilePicture: String?, var profileKey: ByteArray?, var isApproved: Boolean?, var isBlocked: Boolean?, var didApproveMe: Boolean?) {
|
||||
|
||||
internal constructor() : this("", "", null, null)
|
||||
internal constructor() : this("", "", null, null, null, null, null)
|
||||
|
||||
companion object {
|
||||
|
||||
fun fromProto(proto: SignalServiceProtos.ConfigurationMessage.Contact): Contact? {
|
||||
if (!proto.hasName() || !proto.hasProfileKey()) return null
|
||||
if (!proto.hasName()) return null
|
||||
val publicKey = proto.publicKey.toByteArray().toHexString()
|
||||
val name = proto.name
|
||||
val profilePicture = if (proto.hasProfilePicture()) proto.profilePicture else null
|
||||
val profileKey = if (proto.hasProfileKey()) proto.profileKey.toByteArray() else null
|
||||
return Contact(publicKey, name, profilePicture, profileKey)
|
||||
val isApproved = if (proto.hasIsApproved()) proto.isApproved else null
|
||||
val isBlocked = if (proto.hasIsBlocked()) proto.isBlocked else null
|
||||
val didApproveMe = if (proto.hasDidApproveMe()) proto.didApproveMe else null
|
||||
return Contact(publicKey, name, profilePicture, profileKey, isApproved, isBlocked, didApproveMe)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +95,18 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
||||
if (profileKey != null) {
|
||||
result.profileKey = ByteString.copyFrom(profileKey)
|
||||
}
|
||||
val isApproved = isApproved
|
||||
if (isApproved != null) {
|
||||
result.isApproved = isApproved
|
||||
}
|
||||
val isBlocked = isBlocked
|
||||
if (isBlocked != null) {
|
||||
result.isBlocked = isBlocked
|
||||
}
|
||||
val didApproveMe = didApproveMe
|
||||
if (didApproveMe != null) {
|
||||
result.didApproveMe = didApproveMe
|
||||
}
|
||||
return result.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.session.libsession.messaging.messages.control
|
||||
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Log
|
||||
|
||||
class MessageRequestResponse(val isApproved: Boolean) : ControlMessage() {
|
||||
|
||||
override val isSelfSendValid: Boolean = true
|
||||
|
||||
override fun toProto(): SignalServiceProtos.Content? {
|
||||
val messageRequestResponseProto = SignalServiceProtos.MessageRequestResponse.newBuilder()
|
||||
.setIsApproved(isApproved)
|
||||
return try {
|
||||
SignalServiceProtos.Content.newBuilder()
|
||||
.setMessageRequestResponse(messageRequestResponseProto.build())
|
||||
.build()
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Couldn't construct message request response proto from: $this")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "MessageRequestResponse"
|
||||
|
||||
fun fromProto(proto: SignalServiceProtos.Content): MessageRequestResponse? {
|
||||
val messageRequestResponseProto = if (proto.hasMessageRequestResponse()) proto.messageRequestResponse else return null
|
||||
val isApproved = messageRequestResponseProto.isApproved
|
||||
return MessageRequestResponse(isApproved)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,7 @@ public class IncomingMediaMessage {
|
||||
private final long expiresIn;
|
||||
private final boolean expirationUpdate;
|
||||
private final boolean unidentified;
|
||||
private final boolean messageRequestResponse;
|
||||
|
||||
private final DataExtractionNotificationInfoMessage dataExtractionNotification;
|
||||
private final QuoteModel quote;
|
||||
@@ -42,6 +43,7 @@ public class IncomingMediaMessage {
|
||||
long expiresIn,
|
||||
boolean expirationUpdate,
|
||||
boolean unidentified,
|
||||
boolean messageRequestResponse,
|
||||
Optional<String> body,
|
||||
Optional<SignalServiceGroup> group,
|
||||
Optional<List<SignalServiceAttachment>> attachments,
|
||||
@@ -60,6 +62,7 @@ public class IncomingMediaMessage {
|
||||
this.dataExtractionNotification = dataExtractionNotification.orNull();
|
||||
this.quote = quote.orNull();
|
||||
this.unidentified = unidentified;
|
||||
this.messageRequestResponse = messageRequestResponse;
|
||||
|
||||
if (group.isPresent()) this.groupId = Address.fromSerialized(GroupUtil.INSTANCE.getEncodedId(group.get()));
|
||||
else this.groupId = null;
|
||||
@@ -78,7 +81,7 @@ public class IncomingMediaMessage {
|
||||
Optional<List<LinkPreview>> linkPreviews)
|
||||
{
|
||||
return new IncomingMediaMessage(from, message.getSentTimestamp(), -1, expiresIn, false,
|
||||
false, Optional.fromNullable(message.getText()), group, Optional.fromNullable(attachments), quote, Optional.absent(), linkPreviews, Optional.absent());
|
||||
false, false, Optional.fromNullable(message.getText()), group, Optional.fromNullable(attachments), quote, Optional.absent(), linkPreviews, Optional.absent());
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
@@ -150,4 +153,8 @@ public class IncomingMediaMessage {
|
||||
public boolean isUnidentified() {
|
||||
return unidentified;
|
||||
}
|
||||
|
||||
public boolean isMessageRequestResponse() {
|
||||
return messageRequestResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ object MessageReceiver {
|
||||
ExpirationTimerUpdate.fromProto(proto) ?:
|
||||
ConfigurationMessage.fromProto(proto) ?:
|
||||
UnsendRequest.fromProto(proto) ?:
|
||||
MessageRequestResponse.fromProto(proto) ?:
|
||||
CallMessage.fromProto(proto) ?:
|
||||
VisibleMessage.fromProto(proto) ?: throw Error.UnknownMessage
|
||||
// Ignore self send if needed
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package org.session.libsession.messaging.sending_receiving
|
||||
|
||||
import android.text.TextUtils
|
||||
import org.session.libsession.avatars.AvatarHelper
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.*
|
||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.control.DataExtractionNotification
|
||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||
import org.session.libsession.messaging.messages.control.ReadReceipt
|
||||
import org.session.libsession.messaging.messages.control.TypingIndicator
|
||||
import org.session.libsession.messaging.messages.control.UnsendRequest
|
||||
import org.session.libsession.messaging.messages.visible.Attachment
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment
|
||||
@@ -16,7 +24,12 @@ import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPol
|
||||
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
|
||||
import org.session.libsession.messaging.utilities.WebRtcUtils
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.utilities.*
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupRecord
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.ProfileKeyUtil
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.crypto.ecc.DjbECPrivateKey
|
||||
import org.session.libsignal.crypto.ecc.DjbECPublicKey
|
||||
@@ -29,8 +42,7 @@ import org.session.libsignal.utilities.guava.Optional
|
||||
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import java.util.LinkedList
|
||||
|
||||
internal fun MessageReceiver.isBlocked(publicKey: String): Boolean {
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
@@ -47,6 +59,7 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content,
|
||||
is DataExtractionNotification -> handleDataExtractionNotification(message)
|
||||
is ConfigurationMessage -> handleConfigurationMessage(message)
|
||||
is UnsendRequest -> handleUnsendRequest(message)
|
||||
is MessageRequestResponse -> handleMessageRequestResponse(message)
|
||||
is VisibleMessage -> handleVisibleMessage(message, proto, openGroupID)
|
||||
is CallMessage -> handleCallMessage(message)
|
||||
}
|
||||
@@ -119,13 +132,18 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) {
|
||||
&& !TextSecurePreferences.shouldUpdateProfile(context, message.sentTimestamp!!)) return
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
if (userPublicKey == null || message.sender != storage.getUserPublicKey()) return
|
||||
|
||||
val firstTimeSync = !TextSecurePreferences.getConfigurationMessageSynced(context)
|
||||
|
||||
TextSecurePreferences.setConfigurationMessageSynced(context, true)
|
||||
TextSecurePreferences.setLastProfileUpdateTime(context, message.sentTimestamp!!)
|
||||
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
|
||||
for (closedGroup in message.closedGroups) {
|
||||
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue
|
||||
handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, closedGroup.publicKey, closedGroup.name,
|
||||
closedGroup.encryptionKeyPair!!, closedGroup.members, closedGroup.admins, message.sentTimestamp!!, closedGroup.expirationTimer)
|
||||
if (firstTimeSync) {
|
||||
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
|
||||
for (closedGroup in message.closedGroups) {
|
||||
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue
|
||||
handleNewClosedGroup(message.sender!!, message.sentTimestamp!!, closedGroup.publicKey, closedGroup.name,
|
||||
closedGroup.encryptionKeyPair!!, closedGroup.members, closedGroup.admins, message.sentTimestamp!!, closedGroup.expirationTimer)
|
||||
}
|
||||
}
|
||||
val allV2OpenGroups = storage.getAllV2OpenGroups().map { it.value.joinURL }
|
||||
for (openGroup in message.openGroups) {
|
||||
@@ -167,6 +185,10 @@ fun MessageReceiver.handleUnsendRequest(message: UnsendRequest) {
|
||||
SSKEnvironment.shared.notificationManager.updateNotification(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleMessageRequestResponse(message: MessageRequestResponse) {
|
||||
MessagingModuleConfiguration.shared.storage.insertMessageRequestResponse(message)
|
||||
}
|
||||
//endregion
|
||||
|
||||
// region Visible Messages
|
||||
@@ -174,28 +196,33 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
val messageSender: String? = message.sender
|
||||
// Get or create thread
|
||||
// FIXME: In case this is an open group this actually * doesn't * create the thread if it doesn't yet
|
||||
// exist. This is intentional, but it's very non-obvious.
|
||||
val threadID = storage.getOrCreateThreadIdFor(message.syncTarget
|
||||
?: message.sender!!, message.groupPublicKey, openGroupID)
|
||||
?: messageSender!!, message.groupPublicKey, openGroupID)
|
||||
if (threadID < 0) {
|
||||
// Thread doesn't exist; should only be reached in a case where we are processing open group messages for a no longer existent thread
|
||||
throw MessageReceiver.Error.NoThread
|
||||
}
|
||||
// Update profile if needed
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(messageSender!!), false)
|
||||
val profile = message.profile
|
||||
if (profile != null && userPublicKey != message.sender) {
|
||||
if (profile != null && userPublicKey != messageSender) {
|
||||
val profileManager = SSKEnvironment.shared.profileManager
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(message.sender!!), false)
|
||||
val name = profile.displayName!!
|
||||
if (name.isNotEmpty()) {
|
||||
profileManager.setName(context, recipient, name)
|
||||
}
|
||||
val newProfileKey = profile.profileKey
|
||||
if (newProfileKey?.isNotEmpty() == true && (newProfileKey.size == 16 || newProfileKey.size == 32) && profile.profilePictureURL?.isNotEmpty() == true
|
||||
&& (recipient.profileKey == null || !MessageDigest.isEqual(recipient.profileKey, newProfileKey))) {
|
||||
profileManager.setProfileKey(context, recipient, newProfileKey)
|
||||
|
||||
val needsProfilePicture = !AvatarHelper.avatarFileExists(context, Address.fromSerialized(messageSender))
|
||||
val profileKeyValid = newProfileKey?.isNotEmpty() == true && (newProfileKey.size == 16 || newProfileKey.size == 32) && profile.profilePictureURL?.isNotEmpty() == true
|
||||
val profileKeyChanged = (recipient.profileKey == null || !MessageDigest.isEqual(recipient.profileKey, newProfileKey))
|
||||
|
||||
if ((profileKeyValid && profileKeyChanged) || (profileKeyValid && needsProfilePicture)) {
|
||||
profileManager.setProfileKey(context, recipient, newProfileKey!!)
|
||||
profileManager.setUnidentifiedAccessMode(context, recipient, Recipient.UnidentifiedAccessMode.UNKNOWN)
|
||||
profileManager.setProfilePictureURL(context, recipient, profile.profilePictureURL!!)
|
||||
}
|
||||
@@ -276,6 +303,8 @@ private fun MessageReceiver.handleClosedGroupControlMessage(message: ClosedGroup
|
||||
|
||||
private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMessage) {
|
||||
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.New ?: return
|
||||
val recipient = Recipient.from(MessagingModuleConfiguration.shared.context, Address.fromSerialized(message.sender!!), false)
|
||||
if (!recipient.isApproved) return
|
||||
val groupPublicKey = kind.publicKey.toByteArray().toHexString()
|
||||
val members = kind.members.map { it.toByteArray().toHexString() }
|
||||
val admins = kind.admins.map { it.toByteArray().toHexString() }
|
||||
|
||||
@@ -154,6 +154,8 @@ interface TextSecurePreferences {
|
||||
fun setLastOpenDate()
|
||||
fun hasSeenLinkPreviewSuggestionDialog(): Boolean
|
||||
fun setHasSeenLinkPreviewSuggestionDialog()
|
||||
fun hasHiddenMessageRequests(): Boolean
|
||||
fun setHasHiddenMessageRequests()
|
||||
fun setShownCallWarning(): Boolean
|
||||
fun setShownCallNotification(): Boolean
|
||||
fun isCallNotificationsEnabled(): Boolean
|
||||
@@ -233,6 +235,7 @@ interface TextSecurePreferences {
|
||||
const val CONFIGURATION_SYNCED = "pref_configuration_synced"
|
||||
const val LAST_PROFILE_UPDATE_TIME = "pref_last_profile_update_time"
|
||||
const val LAST_OPEN_DATE = "pref_last_open_date"
|
||||
const val HAS_HIDDEN_MESSAGE_REQUESTS = "pref_message_requests_hidden"
|
||||
const val CALL_NOTIFICATIONS_ENABLED = "pref_call_notifications_enabled"
|
||||
const val SHOWN_CALL_WARNING = "pref_shown_call_warning" // call warning is user-facing warning of enabling calls
|
||||
const val SHOWN_CALL_NOTIFICATION = "pref_shown_call_notification" // call notification is a promp to check privacy settings
|
||||
@@ -879,6 +882,16 @@ interface TextSecurePreferences {
|
||||
setBooleanPreference(context, "has_seen_link_preview_suggestion_dialog", true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun hasHiddenMessageRequests(context: Context): Boolean {
|
||||
return getBooleanPreference(context, HAS_HIDDEN_MESSAGE_REQUESTS, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeHasHiddenMessageRequests(context: Context) {
|
||||
removePreference(context, HAS_HIDDEN_MESSAGE_REQUESTS)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setShownCallWarning(context: Context): Boolean {
|
||||
val previousValue = getBooleanPreference(context, SHOWN_CALL_WARNING, false)
|
||||
@@ -1473,6 +1486,14 @@ class AppTextSecurePreferences @Inject constructor(
|
||||
return previousValue != setValue
|
||||
}
|
||||
|
||||
override fun hasHiddenMessageRequests(): Boolean {
|
||||
return getBooleanPreference(TextSecurePreferences.HAS_HIDDEN_MESSAGE_REQUESTS, false)
|
||||
}
|
||||
|
||||
override fun setHasHiddenMessageRequests() {
|
||||
setBooleanPreference(TextSecurePreferences.HAS_HIDDEN_MESSAGE_REQUESTS, true)
|
||||
}
|
||||
|
||||
override fun clearAll() {
|
||||
getDefaultSharedPreferences(context).edit().clear().commit()
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
public long mutedUntil = 0;
|
||||
public int notifyType = 0;
|
||||
private boolean blocked = false;
|
||||
private boolean approved = false;
|
||||
private boolean approvedMe = false;
|
||||
private VibrateState messageVibrate = VibrateState.DEFAULT;
|
||||
private VibrateState callVibrate = VibrateState.DEFAULT;
|
||||
private int expireMessages = 0;
|
||||
@@ -141,6 +143,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
this.callRingtone = stale.callRingtone;
|
||||
this.mutedUntil = stale.mutedUntil;
|
||||
this.blocked = stale.blocked;
|
||||
this.approved = stale.approved;
|
||||
this.approvedMe = stale.approvedMe;
|
||||
this.messageVibrate = stale.messageVibrate;
|
||||
this.callVibrate = stale.callVibrate;
|
||||
this.expireMessages = stale.expireMessages;
|
||||
@@ -169,6 +173,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
this.callRingtone = details.get().callRingtone;
|
||||
this.mutedUntil = details.get().mutedUntil;
|
||||
this.blocked = details.get().blocked;
|
||||
this.approved = details.get().approved;
|
||||
this.approvedMe = details.get().approvedMe;
|
||||
this.messageVibrate = details.get().messageVibrateState;
|
||||
this.callVibrate = details.get().callVibrateState;
|
||||
this.expireMessages = details.get().expireMessages;
|
||||
@@ -570,6 +576,30 @@ public class Recipient implements RecipientModifiedListener {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public synchronized boolean isApproved() {
|
||||
return approved;
|
||||
}
|
||||
|
||||
public void setApproved(boolean approved) {
|
||||
synchronized (this) {
|
||||
this.approved = approved;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public synchronized boolean hasApprovedMe() {
|
||||
return approvedMe;
|
||||
}
|
||||
|
||||
public void setHasApprovedMe(boolean approvedMe) {
|
||||
synchronized (this) {
|
||||
this.approvedMe = approvedMe;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public synchronized VibrateState getMessageVibrate() {
|
||||
return messageVibrate;
|
||||
}
|
||||
@@ -779,6 +809,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
|
||||
public static class RecipientSettings {
|
||||
private final boolean blocked;
|
||||
private final boolean approved;
|
||||
private final boolean approvedMe;
|
||||
private final long muteUntil;
|
||||
private final int notifyType;
|
||||
private final VibrateState messageVibrateState;
|
||||
@@ -801,7 +833,7 @@ public class Recipient implements RecipientModifiedListener {
|
||||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
private final boolean forceSmsSelection;
|
||||
|
||||
public RecipientSettings(boolean blocked, long muteUntil,
|
||||
public RecipientSettings(boolean blocked, boolean approved, boolean approvedMe, long muteUntil,
|
||||
int notifyType,
|
||||
@NonNull VibrateState messageVibrateState,
|
||||
@NonNull VibrateState callVibrateState,
|
||||
@@ -824,6 +856,8 @@ public class Recipient implements RecipientModifiedListener {
|
||||
boolean forceSmsSelection)
|
||||
{
|
||||
this.blocked = blocked;
|
||||
this.approved = approved;
|
||||
this.approvedMe = approvedMe;
|
||||
this.muteUntil = muteUntil;
|
||||
this.notifyType = notifyType;
|
||||
this.messageVibrateState = messageVibrateState;
|
||||
@@ -855,6 +889,14 @@ public class Recipient implements RecipientModifiedListener {
|
||||
return blocked;
|
||||
}
|
||||
|
||||
public boolean isApproved() {
|
||||
return approved;
|
||||
}
|
||||
|
||||
public boolean hasApprovedMe() {
|
||||
return approvedMe;
|
||||
}
|
||||
|
||||
public long getMuteUntil() {
|
||||
return muteUntil;
|
||||
}
|
||||
|
||||
@@ -171,6 +171,8 @@ class RecipientProvider {
|
||||
@Nullable final VibrateState messageVibrateState;
|
||||
@Nullable final VibrateState callVibrateState;
|
||||
final boolean blocked;
|
||||
final boolean approved;
|
||||
final boolean approvedMe;
|
||||
final int expireMessages;
|
||||
@NonNull final List<Recipient> participants;
|
||||
@Nullable final String profileName;
|
||||
@@ -201,6 +203,8 @@ class RecipientProvider {
|
||||
this.messageVibrateState = settings != null ? settings.getMessageVibrateState() : null;
|
||||
this.callVibrateState = settings != null ? settings.getCallVibrateState() : null;
|
||||
this.blocked = settings != null && settings.isBlocked();
|
||||
this.approved = settings != null && settings.isApproved();
|
||||
this.approvedMe = settings != null && settings.hasApprovedMe();
|
||||
this.expireMessages = settings != null ? settings.getExpireMessages() : 0;
|
||||
this.participants = participants == null ? new LinkedList<>() : participants;
|
||||
this.profileName = settings != null ? settings.getProfileName() : null;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- MessageRecord -->
|
||||
<string name="MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported">Received a message encrypted using an old version of Session that is no longer supported. Please ask the sender to update to the most recent version and resend the message.</string>
|
||||
<string name="MessageRecord_left_group">You have left the group.</string>
|
||||
<string name="MessageRecord_you_updated_group">You updated the group.</string>
|
||||
<string name="MessageRecord_you_created_a_new_group">You created a new group.</string>
|
||||
<string name="MessageRecord_s_added_you_to_the_group">%1$s added you to the group.</string>
|
||||
<string name="MessageRecord_you_renamed_the_group_to_s">You renamed the group to %1$s</string>
|
||||
@@ -14,25 +12,15 @@
|
||||
<string name="MessageRecord_s_removed_s_from_the_group">%1$s removed %2$s from the group.</string>
|
||||
<string name="MessageRecord_you_were_removed_from_the_group">You were removed from the group.</string>
|
||||
<string name="MessageRecord_you">You</string>
|
||||
<string name="MessageRecord_you_called">You called</string>
|
||||
<string name="MessageRecord_called_you">Contact called</string>
|
||||
<string name="MessageRecord_missed_call">Missed call</string>
|
||||
<string name="MessageRecord_s_updated_group">%s updated the group.</string>
|
||||
<string name="MessageRecord_s_called_you">%s called you</string>
|
||||
<string name="MessageRecord_called_s">Called %s</string>
|
||||
<string name="MessageRecord_missed_call_from">Missed call from %s</string>
|
||||
<string name="MessageRecord_s_joined_signal">%s is on Session!</string>
|
||||
<string name="MessageRecord_you_disabled_disappearing_messages">You disabled disappearing messages.</string>
|
||||
<string name="MessageRecord_s_disabled_disappearing_messages">%1$s disabled disappearing messages.</string>
|
||||
<string name="MessageRecord_you_set_disappearing_message_time_to_s">You set the disappearing message timer to %1$s</string>
|
||||
<string name="MessageRecord_s_set_disappearing_message_time_to_s">%1$s set the disappearing message timer to %2$s</string>
|
||||
<string name="MessageRecord_s_took_a_screenshot">%1$s took a screenshot.</string>
|
||||
<string name="MessageRecord_media_saved_by_s">Media saved by %1$s.</string>
|
||||
<string name="MessageRecord_your_safety_number_with_s_has_changed">Your safety number with %s has changed.</string>
|
||||
<string name="MessageRecord_you_marked_your_safety_number_with_s_verified">You marked your safety number with %s verified</string>
|
||||
<string name="MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device">You marked your safety number with %s verified from another device</string>
|
||||
<string name="MessageRecord_you_marked_your_safety_number_with_s_unverified">You marked your safety number with %s unverified</string>
|
||||
<string name="MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device">You marked your safety number with %s unverified from another device</string>
|
||||
|
||||
<!-- expiration -->
|
||||
<string name="expiration_off">Off</string>
|
||||
|
||||
Reference in New Issue
Block a user