Fix/ses 3326 unpin legacy groups (#949)

* SES-3326 ability to unpin legacy group post deprecation

* Reusing naming logic for contacts and recipients

Should fix SES-3323 and SES-3320
pull/1710/head
ThomasSession 2 months ago committed by GitHub
parent 1be1278a6b
commit 2a7b08fe64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -343,7 +343,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
if (latestRecipient.recipient != null) {
val contactPublicKey = latestRecipient.recipient.address.serialize()
val contactDisplayName = getUserDisplayName(contactPublicKey)
val contactDisplayName = viewModel.getUserName(contactPublicKey)
supportActionBar?.title = contactDisplayName
binding.remoteRecipientName.text = contactDisplayName
@ -440,12 +440,6 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
binding.contactAvatar.isVisible = false
}
private fun getUserDisplayName(publicKey: String): String {
val contact =
DatabaseComponent.get(this).sessionContactDatabase().getContactWithAccountID(publicKey)
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
}
override fun onStop() {
super.onStop()
uiJob?.cancel()

@ -55,7 +55,7 @@ public class FromTextView extends EmojiTextView {
if (recipient.isLocalNumber()) {
builder.append(getContext().getString(R.string.noteToSelf));
} else if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
} else if (!TextUtils.isEmpty(recipient.getProfileName())) {
SpannableString profileName = new SpannableString(" (~" + recipient.getProfileName() + ") ");
profileName.setSpan(new CenterAlignedRelativeSizeSpan(0.75f), 0, profileName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
profileName.setSpan(new TypefaceSpan("sans-serif-light"), 0, profileName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

@ -7,28 +7,23 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import android.widget.RelativeLayout
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.engine.DiskCacheStrategy
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewProfilePictureBinding
import org.session.libsession.avatars.ContactColors
import org.session.libsession.avatars.PlaceholderAvatarPhoto
import org.session.libsession.avatars.ProfileContactPhoto
import org.session.libsession.avatars.ResourceContactPhoto
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.database.StorageProtocol
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.AppTextSecurePreferences
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.Log
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import dagger.hilt.android.AndroidEntryPoint
import org.session.libsession.database.StorageProtocol
import org.session.libsignal.utilities.AccountId
import org.thoughtcrime.securesms.database.GroupDatabase
import org.thoughtcrime.securesms.database.SessionContactDatabase
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import javax.inject.Inject
@AndroidEntryPoint
@ -47,9 +42,6 @@ class ProfilePictureView @JvmOverloads constructor(
var additionalDisplayName: String? = null
var recipient: Recipient? = null
@Inject
lateinit var contactDatabase: SessionContactDatabase
@Inject
lateinit var groupDatabase: GroupDatabase
@ -91,8 +83,7 @@ class ProfilePictureView @JvmOverloads constructor(
isGroupsV2Recipient: Boolean = false,
) {
fun getUserDisplayName(publicKey: String): String = prefs.takeIf { userPublicKey == publicKey }?.getProfileName()
?: contactDatabase.getContactWithAccountID(publicKey)?.displayName(Contact.ContactContext.REGULAR)
?: publicKey
?: storage.getContactNameWithAccountID(publicKey)
if (isLegacyGroupRecipient || isGroupsV2Recipient) {
val members = if (isLegacyGroupRecipient) {

@ -11,6 +11,7 @@ import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import com.bumptech.glide.RequestManager
import org.session.libsession.messaging.MessagingModuleConfiguration
class UserView : LinearLayout {
private lateinit var binding: ViewUserBinding
@ -49,8 +50,8 @@ class UserView : LinearLayout {
fun getUserDisplayName(publicKey: String): String {
if (isLocalUser) return context.getString(R.string.you)
val contact = DatabaseComponent.get(context).sessionContactDatabase().getContactWithAccountID(publicKey)
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
return MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(publicKey)
}
val address = user.address.serialize()

@ -87,7 +87,7 @@ class MessageDetailsViewModel @Inject constructor(
sent = dateSent.let(::Date).toString().let { TitledText(R.string.sent, it) },
received = dateReceived.let(::Date).toString().let { TitledText(R.string.received, it) },
error = lokiMessageDatabase.getErrorMessage(id)?.let { TitledText(R.string.theError, it) },
senderInfo = individualRecipient.run { name?.let { TitledText(it, address.serialize()) } },
senderInfo = individualRecipient.run { TitledText(name, address.serialize()) },
sender = individualRecipient,
thread = recipient,
readOnly = isDeprecatedLegacyGroup,

@ -10,21 +10,17 @@ import android.text.style.StyleSpan
import androidx.fragment.app.DialogFragment
import network.loki.messenger.R
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.createSessionDialog
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.ui.getSubbedCharSequence
/** Shown upon sending a message to a user that's blocked. */
class BlockedDialog(private val recipient: Recipient, private val context: Context) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = createSessionDialog {
val contactDB = DatabaseComponent.get(requireContext()).sessionContactDatabase()
val accountID = recipient.address.toString()
val contact = contactDB.getContactWithAccountID(accountID)
val name = contact?.displayName(Contact.ContactContext.REGULAR) ?: accountID
val name = MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(accountID)
val explanationCS = context.getSubbedCharSequence(R.string.blockUnblockName, NAME_KEY to name)
val spannable = SpannableStringBuilder(explanationCS)

@ -162,7 +162,7 @@ class MentionViewModel(
.map { contact ->
Member(
publicKey = contact.accountID,
name = contact.displayName(contactContext).orEmpty(),
name = contact.displayName(contactContext),
isModerator = contact.accountID in moderatorIDs,
isMe = false
)

@ -158,13 +158,13 @@ class ControlMessageView : LinearLayout {
context.showSessionDialog {
val titleTxt = context.getSubbedString(
R.string.callsMissedCallFrom,
NAME_KEY to message.individualRecipient.name!!
NAME_KEY to message.individualRecipient.name
)
title(titleTxt)
val bodyTxt = context.getSubbedCharSequence(
R.string.callsYouMissedCallPermissions,
NAME_KEY to message.individualRecipient.name!!
NAME_KEY to message.individualRecipient.name
)
text(bodyTxt)
@ -187,13 +187,13 @@ class ControlMessageView : LinearLayout {
context.showSessionDialog {
val titleTxt = context.getSubbedString(
R.string.callsMissedCallFrom,
NAME_KEY to message.individualRecipient.name!!
NAME_KEY to message.individualRecipient.name
)
title(titleTxt)
val bodyTxt = context.getSubbedCharSequence(
R.string.callsMicrophonePermissionsRequired,
NAME_KEY to message.individualRecipient.name!!
NAME_KEY to message.individualRecipient.name
)
text(bodyTxt)

@ -19,6 +19,7 @@ import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
import org.thoughtcrime.securesms.database.SessionContactDatabase
import com.bumptech.glide.RequestManager
import org.session.libsession.utilities.truncateIdForDisplay
import org.thoughtcrime.securesms.mms.SlideDeck
import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.getAccentColor
@ -76,7 +77,7 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
val authorDisplayName =
if (quoteIsLocalUser) context.getString(R.string.you)
else author?.displayName(Contact.contextForRecipient(thread)) ?: "${authorPublicKey.take(4)}...${authorPublicKey.takeLast(4)}"
else author?.displayName(Contact.contextForRecipient(thread)) ?: truncateIdForDisplay(authorPublicKey)
binding.quoteViewAuthorTextView.text = authorDisplayName
binding.quoteViewAuthorTextView.setTextColor(getTextColor(isOutgoingMessage))
// Body

@ -8,6 +8,7 @@ import java.security.MessageDigest
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_PINNED
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_VISIBLE
import network.loki.messenger.libsession_util.getOrNull
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
import network.loki.messenger.libsession_util.util.ExpiryMode
import network.loki.messenger.libsession_util.util.GroupDisplayInfo
@ -17,6 +18,7 @@ import org.session.libsession.avatars.AvatarHelper
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.BlindedIdMapping
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.calls.CallMessageType
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
@ -67,6 +69,7 @@ import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.recipients.Recipient.DisappearingState
import org.session.libsession.utilities.recipients.MessageType
import org.session.libsession.utilities.recipients.getType
import org.session.libsession.utilities.truncateIdForDisplay
import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.messages.SignalServiceAttachmentPointer
@ -1238,6 +1241,17 @@ open class Storage @Inject constructor(
return sessionContactDatabase.getContactWithAccountID(accountID)
}
override fun getContactNameWithAccountID(accountID: String, groupId: AccountId?, contactContext: Contact.ContactContext): String {
val contact = sessionContactDatabase.getContactWithAccountID(accountID)
// first attempt to get the name from the contact
val userName: String? = contact?.displayName(contactContext)
?: if(groupId != null){
configFactory.withGroupConfigs(groupId) { it.groupMembers.getOrNull(accountID)?.name }
} else null
return userName ?: truncateIdForDisplay(accountID)
}
override fun getAllContacts(): Set<Contact> {
return sessionContactDatabase.getAllContacts()
}

@ -94,17 +94,8 @@ public class ThreadRecord extends DisplayRecord {
this.groupThreadStatus = groupThreadStatus;
}
public @Nullable Uri getSnippetUri() {
return snippetUri;
}
private String getName() {
String name = getRecipient().getName();
if (name == null) {
Log.w("ThreadRecord", "Got a null name - using: Unknown");
name = "Unknown";
}
return name;
return getRecipient().getName();
}

@ -20,7 +20,6 @@ import network.loki.messenger.libsession_util.util.GroupMember
import org.session.libsession.database.StorageProtocol
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.ConfigUpdateNotification
import org.session.libsession.utilities.getMemberName
import org.session.libsignal.utilities.AccountId
import java.util.EnumSet
@ -78,7 +77,7 @@ abstract class BaseGroupMembersViewModel (
val name = if (isMyself) {
context.getString(R.string.you)
} else {
member.getMemberName(configFactory)
storage.getContactNameWithAccountID(member.accountId.hexString, groupId)
}
val highlightStatus = status in EnumSet.of(

@ -135,7 +135,7 @@ class GroupManagerV2Impl @Inject constructor(
for (member in memberAsRecipients) {
configs.groupMembers.set(
configs.groupMembers.getOrConstruct(member.address.serialize()).apply {
setName(member.name.orEmpty())
setName(member.name)
setProfilePic(member.profileAvatar?.let { url ->
member.profileKey?.let { key -> UserPic(url, key) }
} ?: UserPic.DEFAULT)

@ -1,48 +0,0 @@
package org.thoughtcrime.securesms.groups
import android.content.Context
import androidx.annotation.WorkerThread
import org.greenrobot.eventbus.EventBus
import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import java.util.*
//TODO Refactor so methods declare specific type of checked exceptions and not generalized Exception.
object OpenGroupUtilities {
private const val TAG = "OpenGroupUtilities"
/**
* Pulls the general public chat data from the server and updates related records.
* Fires [GroupInfoUpdatedEvent] on [EventBus] upon success.
*
* Consider using [org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker] for lazy approach.
*/
@JvmStatic
@WorkerThread
@Throws(Exception::class)
fun updateGroupInfo(context: Context, server: String, room: String) {
val groupId = GroupUtil.getEncodedOpenGroupID("$server.$room".toByteArray())
if (!DatabaseComponent.get(context).groupDatabase().hasGroup(groupId)) {
throw IllegalStateException("Attempt to update open group info for non-existent DB record: $groupId")
}
val info = OpenGroupApi.getRoomInfo(room, server).get() // store info again?
EventBus.getDefault().post(GroupInfoUpdatedEvent(server, room = room))
}
/**
* Return a generated name for users in the style of `$name (...$hex.takeLast(8))` for public groups
*/
@JvmStatic
fun getDisplayName(recipient: Recipient): String {
return String.format(Locale.ROOT, PUBLIC_GROUP_STRING_FORMAT, recipient.name, recipient.address.serialize().takeLast(8))
}
const val PUBLIC_GROUP_STRING_FORMAT = "%s (...%s)"
data class GroupInfoUpdatedEvent(val url: String, val channel: Long = -1, val room: String = "")
}

@ -40,7 +40,7 @@ class CreateLegacyGroupViewModel @Inject constructor(
fun filter(query: String): List<Recipient> {
return _recipients.value?.filter {
it.address.serialize().contains(query, ignoreCase = true) || it.name?.contains(query, ignoreCase = true) == true
it.address.serialize().contains(query, ignoreCase = true) || it.name.contains(query, ignoreCase = true)
} ?: emptyList()
}
}

@ -152,7 +152,7 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto
&& !isDeprecatedLegacyGroup
binding.markAllAsReadTextView.setOnClickListener(this)
binding.pinTextView.isVisible = !thread.isPinned && !isDeprecatedLegacyGroup
binding.unpinTextView.isVisible = thread.isPinned && !isDeprecatedLegacyGroup
binding.unpinTextView.isVisible = thread.isPinned
binding.pinTextView.setOnClickListener(this)
binding.unpinTextView.setOnClickListener(this)
}

@ -84,7 +84,7 @@ class UserDetailsBottomSheet: BottomSheetDialogFragment() {
else -> return@setOnEditorActionListener false
}
}
nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally
nameTextView.text = recipient.name
nameEditIcon.isVisible = threadRecipient.isContactRecipient
&& !threadRecipient.isCommunityInboxRecipient
@ -140,7 +140,7 @@ class UserDetailsBottomSheet: BottomSheetDialogFragment() {
val contact = storage.getContactWithAccountID(publicKey) ?: Contact(publicKey)
contact.nickname = newNickName
storage.setContact(contact)
nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally
nameTextView.text = recipient.name
}
@SuppressLint("ServiceCast")

@ -146,7 +146,7 @@ fun ContentView.bindModel(query: String?, model: Message) = binding.apply {
}
fun Recipient.getSearchName(): String =
name?.takeIf { it.isNotEmpty() && !it.looksLikeAccountId }
name.takeIf { it.isNotEmpty() && !it.looksLikeAccountId }
?: address.serialize().let(::truncateIdForDisplay)
fun Contact.getSearchName(): String =

@ -8,6 +8,7 @@ import android.text.SpannableStringBuilder
import androidx.core.app.NotificationCompat
import com.squareup.phrase.Phrase
import network.loki.messenger.R
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.NotificationPrivacyPreference
import org.session.libsession.utilities.StringSubstitutionConstants.CONVERSATION_COUNT_KEY
@ -102,11 +103,9 @@ class MultipleRecipientNotificationBuilder(context: Context, privacy: Notificati
* @param openGroupRecipient whether in an open group context
*/
private fun getGroupDisplayName(recipient: Recipient, openGroupRecipient: Boolean): String {
val contactDB = get(context).sessionContactDatabase()
val accountID = recipient.address.serialize()
val contact = contactDB.getContactWithAccountID(accountID) ?: return accountID
val displayName = contact.displayName(if (openGroupRecipient) Contact.ContactContext.OPEN_GROUP else Contact.ContactContext.REGULAR)
if (displayName == null) { return accountID }
return displayName
return MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(
accountID = recipient.address.serialize(),
contactContext = if (openGroupRecipient) Contact.ContactContext.OPEN_GROUP else Contact.ContactContext.REGULAR
)
}
}

@ -27,6 +27,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.session.libsession.avatars.ContactPhoto;
import org.session.libsession.messaging.MessagingModuleConfiguration;
import org.session.libsession.messaging.contacts.Contact;
import org.session.libsession.utilities.NotificationPrivacyPreference;
import org.session.libsession.utilities.Util;
@ -330,12 +331,10 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
* @param openGroupRecipient whether in an open group context
*/
private String getGroupDisplayName(Recipient recipient, boolean openGroupRecipient) {
SessionContactDatabase contactDB = DatabaseComponent.get(context).sessionContactDatabase();
String accountID = recipient.getAddress().serialize();
Contact contact = contactDB.getContactWithAccountID(accountID);
if (contact == null) { return accountID; }
String displayName = contact.displayName(openGroupRecipient ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR);
if (displayName == null) { return accountID; }
return displayName;
return MessagingModuleConfiguration.getShared().getStorage().getContactNameWithAccountID(
recipient.getAddress().serialize(),
null,
openGroupRecipient ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR
);
}
}

@ -163,9 +163,6 @@ final class ReactionRecipientsAdapter extends RecyclerView.Adapter<ReactionRecip
this.remove.setVisibility(canRemove ? View.VISIBLE : View.GONE);
} else {
String name = reaction.getSender().getName();
if (name == null){
name = truncateIdForDisplay(reaction.getSender().getAddress().serialize());
}
this.recipient.setText(name);
this.remove.setVisibility(View.GONE);
}

@ -5,12 +5,16 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import org.session.libsession.database.StorageProtocol
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
import org.webrtc.SurfaceViewRenderer
import javax.inject.Inject
@HiltViewModel
class CallViewModel @Inject constructor(private val callManager: CallManager): ViewModel() {
class CallViewModel @Inject constructor(
private val callManager: CallManager,
private val storage: StorageProtocol,
): ViewModel() {
enum class State {
CALL_PENDING,
@ -65,6 +69,8 @@ class CallViewModel @Inject constructor(private val callManager: CallManager): V
val recipient get() = callManager.recipientEvents
val callStartTime: Long get() = callManager.callStartTime
fun getUserName(accountID: String) = storage.getContactNameWithAccountID(accountID)
fun swapVideos() {
callManager.swapVideos()
}

@ -136,7 +136,7 @@ class MentionViewModelTest {
assertThat(result.members).isEqualTo(threadMembers.mapIndexed { index, m ->
val name =
memberContacts[index].displayName(Contact.ContactContext.OPEN_GROUP).orEmpty()
memberContacts[index].displayName(Contact.ContactContext.OPEN_GROUP)
MentionViewModel.Candidate(
MentionViewModel.Member(m.pubKey, name, m.roles.any { it.isModerator }, isMe = false),

@ -209,6 +209,7 @@ interface StorageProtocol {
// Contacts
fun getContactWithAccountID(accountID: String): Contact?
fun getContactNameWithAccountID(accountID: String, groupId: AccountId? = null, contactContext: Contact.ContactContext = Contact.ContactContext.REGULAR): String
fun getAllContacts(): Set<Contact>
fun setContact(contact: Contact)
fun getRecipientForThread(threadId: Long): Recipient?

@ -3,6 +3,7 @@ package org.session.libsession.messaging.contacts
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.truncateIdForDisplay
@Parcelize
class Contact(
@ -38,12 +39,12 @@ class Contact(
/**
* The name to display in the UI. For local use only.
*/
fun displayName(context: ContactContext): String? = nickname ?: when (context) {
fun displayName(context: ContactContext = ContactContext.REGULAR): String = nickname ?: when (context) {
ContactContext.REGULAR -> name
// In open groups, where it's more likely that multiple users have the same name,
// we display a bit of the Account ID after a user's display name for added context.
ContactContext.OPEN_GROUP -> name?.let { "$it (${accountID.take(4)}...${accountID.takeLast(4)})" }
}
ContactContext.OPEN_GROUP -> name?.let { "$it (${truncateIdForDisplay(accountID)})" }
} ?: truncateIdForDisplay(accountID)
enum class ContactContext {
REGULAR, OPEN_GROUP

@ -32,7 +32,7 @@ class GroupInviteException(
fun format(context: Context, storage: StorageProtocol): CharSequence {
val getInviteeName = { accountId: String ->
storage.getContactWithAccountID(accountId)?.name ?: truncateIdForDisplay(accountId)
storage.getContactNameWithAccountID(accountId)
}
val first = inviteeAccountIds.first().let(getInviteeName)

@ -34,14 +34,8 @@ object UpdateMessageBuilder {
val storage = MessagingModuleConfiguration.shared.storage
private fun getSenderName(senderId: String) = storage.getContactWithAccountID(senderId)
?.displayName(Contact.ContactContext.REGULAR)
?: truncateIdForDisplay(senderId)
private fun getGroupMemberName(groupId: AccountId?, memberId: String) =
storage.getContactWithAccountID(memberId)?.displayName(Contact.ContactContext.REGULAR)
?: groupId?.let{ MessagingModuleConfiguration.shared.configFactory.withGroupConfigs(it) { it.groupMembers.getOrNull(memberId)?.name } }
?: truncateIdForDisplay(memberId)
private fun getGroupMemberName(memberId: String, groupId: AccountId? = null) =
storage.getContactNameWithAccountID(memberId, groupId)
@JvmStatic
fun buildGroupUpdateMessage(
@ -86,19 +80,19 @@ object UpdateMessageBuilder {
}
1 -> {
Phrase.from(context, R.string.legacyGroupMemberNew)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.format()
}
2 -> {
Phrase.from(context, R.string.legacyGroupMemberTwoNew)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(1)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(1), groupV2Id))
.format()
}
else -> {
val newMemberCountMinusOne = newMemberCount - 1
Phrase.from(context, R.string.legacyGroupMemberNewMultiple)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(COUNT_KEY, newMemberCountMinusOne)
.format()
}
@ -126,14 +120,14 @@ object UpdateMessageBuilder {
"" // Return an empty string - we don't want to show the error in the conversation
}
1 -> Phrase.from(context, R.string.groupRemoved)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.format()
2 -> Phrase.from(context, R.string.groupRemovedTwo)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(1)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(1), groupV2Id))
.format()
else -> Phrase.from(context, R.string.groupRemovedMultiple)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(COUNT_KEY, updateData.updatedMembers.size - 1)
.format()
}
@ -150,14 +144,14 @@ object UpdateMessageBuilder {
"" // Return an empty string - we don't want to show the error in the conversation
}
1 -> Phrase.from(context, R.string.groupRemoved)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.format()
2 -> Phrase.from(context, R.string.groupRemovedTwo)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(1)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(1), groupV2Id))
.format()
else -> Phrase.from(context, R.string.groupRemovedMultiple)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(COUNT_KEY, updateData.updatedMembers.size - 1)
.format()
}
@ -173,14 +167,14 @@ object UpdateMessageBuilder {
"" // Return an empty string - we don't want to show the error in the conversation
}
1 -> Phrase.from(context, R.string.groupMemberLeft)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.format()
2 -> Phrase.from(context, R.string.groupMemberLeftTwo)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(1)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(1), groupV2Id))
.format()
else -> Phrase.from(context, R.string.groupMemberLeftMultiple)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.updatedMembers.elementAt(0)))
.put(NAME_KEY, getGroupMemberName(updateData.updatedMembers.elementAt(0), groupV2Id))
.put(COUNT_KEY, updateData.updatedMembers.size - 1)
.format()
}
@ -208,16 +202,16 @@ object UpdateMessageBuilder {
.format()
number == 1 -> Phrase.from(context,
if (historyShared) R.string.groupMemberNewHistory else R.string.groupMemberNew)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.format()
number == 2 && containsUser -> Phrase.from(context,
if (historyShared) R.string.groupMemberNewYouHistoryTwo else R.string.groupInviteYouAndOtherNew)
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first { it != userPublicKey }))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.sessionIds.first { it != userPublicKey }, groupV2Id))
.format()
number == 2 -> Phrase.from(context,
if (historyShared) R.string.groupMemberNewHistoryTwo else R.string.groupMemberNewTwo)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.last()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.sessionIds.last(), groupV2Id))
.format()
containsUser -> Phrase.from(context,
if (historyShared) R.string.groupMemberNewYouHistoryMultiple else R.string.groupInviteYouAndMoreNew)
@ -225,7 +219,7 @@ object UpdateMessageBuilder {
.format()
number > 0 -> Phrase.from(context,
if (historyShared) R.string.groupMemberNewHistoryMultiple else R.string.groupMemberNewMultiple)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.put(COUNT_KEY, updateData.sessionIds.size - 1)
.format()
else -> ""
@ -239,16 +233,16 @@ object UpdateMessageBuilder {
)
number == 1 -> Phrase.from(context,
R.string.adminPromotedToAdmin)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.format()
number == 2 && containsUser -> Phrase.from(context,
R.string.groupPromotedYouTwo)
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first{ it != userPublicKey }))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.sessionIds.first{ it != userPublicKey }, groupV2Id))
.format()
number == 2 -> Phrase.from(context,
R.string.adminTwoPromotedToAdmin)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.last()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.sessionIds.last(), groupV2Id))
.format()
containsUser -> Phrase.from(context,
R.string.groupPromotedYouMultiple)
@ -256,7 +250,7 @@ object UpdateMessageBuilder {
.format()
else -> Phrase.from(context,
R.string.adminMorePromotedToAdmin)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.put(COUNT_KEY, updateData.sessionIds.size - 1)
.format()
}
@ -268,16 +262,16 @@ object UpdateMessageBuilder {
R.string.groupRemovedYouGeneral).format()
number == 1 -> Phrase.from(context,
R.string.groupRemoved)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.format()
number == 2 && containsUser -> Phrase.from(context,
R.string.groupRemovedYouTwo)
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first { it != userPublicKey }))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.sessionIds.first { it != userPublicKey }, groupV2Id))
.format()
number == 2 -> Phrase.from(context,
R.string.groupRemovedTwo)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(OTHER_NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.last()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.put(OTHER_NAME_KEY, getGroupMemberName(updateData.sessionIds.last(), groupV2Id))
.format()
containsUser -> Phrase.from(context,
R.string.groupRemovedYouMultiple)
@ -285,7 +279,7 @@ object UpdateMessageBuilder {
.format()
else -> Phrase.from(context,
R.string.groupRemovedMultiple)
.put(NAME_KEY, getGroupMemberName(groupV2Id, updateData.sessionIds.first()))
.put(NAME_KEY, getGroupMemberName(updateData.sessionIds.first(), groupV2Id))
.put(COUNT_KEY, updateData.sessionIds.size - 1)
.format()
}
@ -295,7 +289,7 @@ object UpdateMessageBuilder {
}
is UpdateMessageData.Kind.GroupInvitation -> {
val approved = configFactory.getGroup(AccountId(updateData.groupAccountId))?.invited == false
val inviterName = updateData.invitingAdminName?.takeIf { it.isNotEmpty() } ?: getGroupMemberName(groupV2Id, updateData.invitingAdminId)
val inviterName = updateData.invitingAdminName?.takeIf { it.isNotEmpty() } ?: getGroupMemberName(updateData.invitingAdminId, groupV2Id)
return if (!approved) {
Phrase.from(context, R.string.messageRequestGroupInvite)
.put(NAME_KEY, inviterName)
@ -336,7 +330,7 @@ object UpdateMessageBuilder {
return ""
}
val senderName = if (isOutgoing) context.getString(R.string.you) else getSenderName(senderId!!)
val senderName = if (isOutgoing) context.getString(R.string.you) else getGroupMemberName(senderId!!)
// Case 1.) Disappearing messages have been turned off..
if (duration <= 0) {
@ -393,7 +387,7 @@ object UpdateMessageBuilder {
kind: DataExtractionNotificationInfoMessage.Kind,
senderId: String? = null): CharSequence {
val senderName = if (senderId != null) getSenderName(senderId) else context.getString(R.string.unknown)
val senderName = if (senderId != null) getGroupMemberName(senderId) else context.getString(R.string.unknown)
return when (kind) {
SCREENSHOT -> Phrase.from(context, R.string.screenshotTaken)
@ -407,9 +401,7 @@ object UpdateMessageBuilder {
}
fun buildCallMessage(context: Context, type: CallMessageType, senderId: String): String {
val senderName =
storage.getContactWithAccountID(senderId)?.displayName(Contact.ContactContext.REGULAR)
?: senderId
val senderName = storage.getContactNameWithAccountID(senderId)
return when (type) {
CALL_INCOMING -> Phrase.from(context, R.string.callsCalledYou).put(NAME_KEY, senderName)

@ -132,21 +132,4 @@ object GroupUtil {
}
return memberMap
}
}
fun GroupMember.getMemberName(config: ConfigFactoryProtocol): String {
return config.withUserConfigs {
it.contacts.get(this.accountId.hexString)?.displayName
?: this.name.takeIf { it.isNotBlank() }
?: truncateIdForDisplay(this.accountId.hexString)
}
}
//todo GROUPSV2 Currently avatars use Recipients to display avatars, meaning unknown groups member are not currently using this avatar below but instead will try to fetch a recipient from the account ID, which won't be found so the unknown icon will be used - We need to have an avatar system that handles low level daat like a url
fun GroupMember.getMemberAvatar(config: ConfigFactoryProtocol): UserPic {
return config.withUserConfigs {
it.contacts.get(this.accountId.hexString)?.profilePicture
?: this.profilePic()
?: UserPic.DEFAULT
}
}

@ -320,7 +320,7 @@ public class Recipient implements RecipientModifiedListener, Cloneable {
if (notify) notifyListeners();
}
public synchronized @Nullable String getName() {
public synchronized @NonNull String getName() {
StorageProtocol storage = MessagingModuleConfiguration.getShared().getStorage();
String accountID = this.address.toString();
if (isGroupOrCommunityRecipient()) {
@ -335,13 +335,9 @@ public class Recipient implements RecipientModifiedListener, Cloneable {
}
} else if (isCommunityInboxRecipient()){
String inboxID = GroupUtil.getDecodedOpenGroupInboxAccountId(accountID);
Contact contact = storage.getContactWithAccountID(inboxID);
if (contact == null) return accountID;
return contact.displayName(Contact.ContactContext.REGULAR);
return storage.getContactNameWithAccountID(inboxID, null, Contact.ContactContext.OPEN_GROUP);
} else {
Contact contact = storage.getContactWithAccountID(accountID);
if (contact == null) return null;
return contact.displayName(Contact.ContactContext.REGULAR);
return storage.getContactNameWithAccountID(accountID, null, Contact.ContactContext.REGULAR);
}
}
@ -523,14 +519,7 @@ public class Recipient implements RecipientModifiedListener, Cloneable {
}
public synchronized String toShortString() {
String name = getName();
if (name != null) return name;
String accountId = address.serialize();
if (accountId.length() < 4) return accountId; // so substrings don't throw out of bounds exceptions
int takeAmount = 4;
String start = accountId.substring(0, takeAmount);
String end = accountId.substring(accountId.length()-takeAmount);
return start+"..."+end;
return getName();
}
public synchronized @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted) {

@ -56,7 +56,7 @@ class RecipientProvider {
@NonNull Recipient getRecipient(@NonNull Context context, @NonNull Address address, @NonNull Optional<RecipientSettings> settings, @NonNull Optional<GroupRecord> groupRecord, boolean asynchronous) {
Recipient cachedRecipient = recipientCache.get(address);
if (cachedRecipient != null && (asynchronous || !cachedRecipient.isResolving()) && ((!groupRecord.isPresent() && !settings.isPresent()) || !cachedRecipient.isResolving() || cachedRecipient.getName() != null)) {
if (cachedRecipient != null && (asynchronous || !cachedRecipient.isResolving()) && ((!groupRecord.isPresent() && !settings.isPresent()) || !cachedRecipient.isResolving())) {
return cachedRecipient;
}

Loading…
Cancel
Save