Feature/username cleanup (#957)

* Centralising username access

* Centralising username logic

* Removing ContactUtil

* Cleaning up shortString

* Making sure the name doesn't overflow in a message view

* Using Lazy to avoid dependency cycle
pull/1710/head
ThomasSession 1 month ago committed by GitHub
parent e10054c4ee
commit 92f1390fad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -58,6 +58,7 @@ import org.session.libsession.utilities.ProfilePictureUtilities;
import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Toaster;
import org.session.libsession.utilities.UsernameUtils;
import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.WindowDebouncer;
import org.session.libsignal.utilities.HTTP;
@ -175,6 +176,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
@Inject LegacyClosedGroupPollerV2 legacyClosedGroupPollerV2;
@Inject LegacyGroupDeprecationManager legacyGroupDeprecationManager;
@Inject CleanupInvitationHandler cleanupInvitationHandler;
@Inject UsernameUtils usernameUtils;
public volatile boolean isAppVisible;
public String KEYGUARD_LOCK_TAG = NonTranslatableStringConstants.APP_NAME + ":KeyguardLock";
@ -264,7 +266,8 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
snodeClock,
textSecurePreferences,
legacyClosedGroupPollerV2,
legacyGroupDeprecationManager
legacyGroupDeprecationManager,
usernameUtils
);
callMessageProcessor = new CallMessageProcessor(this, textSecurePreferences, ProcessLifecycleOwner.get().getLifecycle(), storage);
Log.i(TAG, "onCreate()");

@ -259,7 +259,7 @@ public class MediaPreviewActivity extends ScreenLockActionBarActivity implements
}
if (mediaItem.outgoing) getSupportActionBar().setTitle(getString(R.string.you));
else if (mediaItem.recipient != null) getSupportActionBar().setTitle(mediaItem.recipient.toShortString());
else if (mediaItem.recipient != null) getSupportActionBar().setTitle(mediaItem.recipient.getName());
else getSupportActionBar().setTitle("");
getSupportActionBar().setSubtitle(relativeTimeSpan);

@ -198,10 +198,9 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
// set up the user avatar
TextSecurePreferences.getLocalNumber(this)?.let{
val username = TextSecurePreferences.getProfileName(this) ?: truncateIdForDisplay(it)
binding.userAvatar.apply {
publicKey = it
displayName = username
displayName = viewModel.getCurrentUsername()
update()
}
}
@ -343,7 +342,7 @@ class WebRtcCallActivity : ScreenLockActionBarActivity() {
if (latestRecipient.recipient != null) {
val contactPublicKey = latestRecipient.recipient.address.serialize()
val contactDisplayName = viewModel.getUserName(contactPublicKey)
val contactDisplayName = viewModel.getContactName(contactPublicKey)
supportActionBar?.title = contactDisplayName
binding.remoteRecipientName.text = contactDisplayName

@ -37,7 +37,7 @@ public class FromTextView extends EmojiTextView {
}
public void setText(Recipient recipient, boolean read) {
String fromString = recipient.toShortString();
String fromString = recipient.getName();
int typeface;

@ -21,7 +21,9 @@ 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.UsernameUtils
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.truncateIdForDisplay
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.database.GroupDatabase
import javax.inject.Inject
@ -48,6 +50,9 @@ class ProfilePictureView @JvmOverloads constructor(
@Inject
lateinit var storage: StorageProtocol
@Inject
lateinit var usernameUtils: UsernameUtils
private val profilePicturesCache = mutableMapOf<View, Recipient>()
private val resourcePadding by lazy {
context.resources.getDimensionPixelSize(R.dimen.normal_padding).toFloat()
@ -83,7 +88,7 @@ class ProfilePictureView @JvmOverloads constructor(
isGroupsV2Recipient: Boolean = false,
) {
fun getUserDisplayName(publicKey: String): String = prefs.takeIf { userPublicKey == publicKey }?.getProfileName()
?: storage.getContactNameWithAccountID(publicKey)
?: usernameUtils.getContactNameWithAccountID(publicKey)
if (isLegacyGroupRecipient || isGroupsV2Recipient) {
val members = if (isLegacyGroupRecipient) {
@ -164,7 +169,7 @@ class ProfilePictureView @JvmOverloads constructor(
glide.clear(imageView)
val placeholder = PlaceholderAvatarPhoto(publicKey, displayName ?: "${publicKey.take(4)}...${publicKey.takeLast(4)}")
val placeholder = PlaceholderAvatarPhoto(publicKey, displayName ?: truncateIdForDisplay(publicKey))
if (signalProfilePicture != null && avatar != "0" && avatar != "") {
glide.load(signalProfilePicture)

@ -1,5 +0,0 @@
package org.thoughtcrime.securesms.components.emoji;
public final class EmojiStrings {
public static final String BUST_IN_SILHOUETTE = "\uD83D\uDC64";
}

@ -51,18 +51,6 @@ public class ContactAccessor {
return instance;
}
public String getNameFromContact(Context context, Uri uri) {
return "Anonymous";
}
public ContactData getContactData(Context context, Uri uri) {
return getContactData(context, getNameFromContact(context, uri), Long.parseLong(uri.getLastPathSegment()));
}
private ContactData getContactData(Context context, String displayName, long id) {
return new ContactData(id, displayName);
}
public List<String> getNumbersForThreadSearchFilter(Context context, String constraint) {
LinkedList<String> numberList = new LinkedList<>();
@ -73,19 +61,9 @@ public class ContactAccessor {
}
}
// if (context.getString(R.string.noteToSelf).toLowerCase().contains(constraint.toLowerCase()) &&
// !numberList.contains(TextSecurePreferences.getLocalNumber(context)))
// {
// numberList.add(TextSecurePreferences.getLocalNumber(context));
// }
return numberList;
}
public CharSequence phoneTypeToString(Context mContext, int type, CharSequence label) {
return label;
}
public static class NumberData implements Parcelable {
public static final Parcelable.Creator<NumberData> CREATOR = new Parcelable.Creator<NumberData>() {
@ -101,10 +79,6 @@ public class ContactAccessor {
public final String number;
public final String type;
public NumberData(String type, String number) {
this.type = type;
this.number = number;
}
public NumberData(Parcel in) {
number = in.readString();
@ -137,12 +111,6 @@ public class ContactAccessor {
public final String name;
public final List<NumberData> numbers;
public ContactData(long id, String name) {
this.id = id;
this.name = name;
this.numbers = new LinkedList<NumberData>();
}
public ContactData(Parcel in) {
id = in.readLong();
name = in.readString();

@ -33,9 +33,9 @@ class ContactSelectionListLoader(
override fun loadInBackground(): List<ContactSelectionListItem> {
val contacts = ContactUtilities.getAllContacts(context).filter {
if (filter.isNullOrEmpty()) return@filter true
it.toShortString().contains(filter.trim(), true) || it.address.serialize().contains(filter.trim(), true)
it.name.contains(filter.trim(), true) || it.address.serialize().contains(filter.trim(), true)
}.sortedBy {
it.toShortString()
it.name
}
val list = mutableListOf<ContactSelectionListItem>()
if (isFlagSet(DisplayMode.FLAG_CLOSED_GROUPS)) {

@ -1,42 +0,0 @@
package org.thoughtcrime.securesms.contacts;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import org.session.libsession.utilities.Contact;
import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
import org.thoughtcrime.securesms.util.SpanUtil;
import network.loki.messenger.R;
public final class ContactUtil {
public static @NonNull CharSequence getStringSummary(@NonNull Context context, @NonNull Contact contact) {
String contactName = ContactUtil.getDisplayName(contact);
if (!TextUtils.isEmpty(contactName)) {
return EmojiStrings.BUST_IN_SILHOUETTE + " " + contactName;
}
return SpanUtil.italic(context.getString(R.string.unknown));
}
private static @NonNull String getDisplayName(@Nullable Contact contact) {
if (contact == null) {
return "";
}
if (!TextUtils.isEmpty(contact.getName().getDisplayName())) {
return contact.getName().getDisplayName();
}
if (!TextUtils.isEmpty(contact.getOrganization())) {
return contact.getOrganization();
}
return "";
}
}

@ -176,7 +176,7 @@ public class ContactsCursorLoader extends CursorLoader {
ThreadDatabase.Reader reader = threadDatabase.readerFor(rawConversations);
ThreadRecord threadRecord;
while ((threadRecord = reader.getNext()) != null) {
recentConversations.addRow(new Object[] { threadRecord.getRecipient().toShortString(),
recentConversations.addRow(new Object[] { threadRecord.getRecipient().getName(),
threadRecord.getRecipient().getAddress().serialize(),
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
"",

@ -5,17 +5,21 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import com.bumptech.glide.RequestManager
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewUserBinding
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import com.bumptech.glide.RequestManager
import org.session.libsession.messaging.MessagingModuleConfiguration
import javax.inject.Inject
@AndroidEntryPoint
class UserView : LinearLayout {
private lateinit var binding: ViewUserBinding
@Inject
lateinit var usernameUtils: UsernameUtils
enum class ActionIndicator {
None,
Menu,
@ -51,7 +55,7 @@ class UserView : LinearLayout {
fun getUserDisplayName(publicKey: String): String {
if (isLocalUser) return context.getString(R.string.you)
return MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(publicKey)
return usernameUtils.getContactNameWithAccountID(publicKey)
}
val address = user.address.serialize()

@ -87,7 +87,7 @@ class ConversationActionBarView @JvmOverloads constructor(
fun update(recipient: Recipient, openGroup: OpenGroup? = null, config: ExpirationConfiguration? = null) {
binding.profilePictureView.update(recipient)
binding.conversationTitleView.text = recipient.takeUnless { it.isLocalNumber }?.toShortString() ?: context.getString(R.string.noteToSelf)
binding.conversationTitleView.text = recipient.takeUnless { it.isLocalNumber }?.name ?: context.getString(R.string.noteToSelf)
updateSubtitle(recipient, openGroup, config)
binding.conversationTitleContainer.modifyLayoutParams<MarginLayoutParams> {

@ -880,7 +880,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
if (shouldShowLegacy) {
val txt = Phrase.from(this, R.string.disappearingMessagesLegacy)
.put(NAME_KEY, legacyRecipient!!.toShortString())
.put(NAME_KEY, legacyRecipient!!.name)
.format()
binding.outdatedDisappearingBannerTextView.text = txt
}
@ -1265,12 +1265,12 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
binding.conversationRecyclerView.isVisible = false
binding.placeholderText.text = when (groupThreadStatus) {
GroupThreadStatus.Kicked -> Phrase.from(this, R.string.groupRemovedYou)
.put(GROUP_NAME_KEY, recipient.toShortString())
.put(GROUP_NAME_KEY, recipient.name)
.format()
.toString()
GroupThreadStatus.Destroyed -> Phrase.from(this, R.string.groupDeletedMemberDescription)
.put(GROUP_NAME_KEY, recipient.toShortString())
.put(GROUP_NAME_KEY, recipient.name)
.format()
.toString()
@ -1294,14 +1294,14 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
// If we're trying to message someone who has blocked community message requests
blindedRecipient?.blocksCommunityMessageRequests == true -> {
Phrase.from(applicationContext, R.string.messageRequestsTurnedOff)
.put(NAME_KEY, recipient.toShortString())
.put(NAME_KEY, recipient.name)
.format()
}
// 10n1 and groups
recipient.is1on1 || recipient.isGroupOrCommunityRecipient -> {
Phrase.from(applicationContext, R.string.groupNoMessages)
.put(GROUP_NAME_KEY, recipient.toShortString())
.put(GROUP_NAME_KEY, recipient.name)
.format()
}
@ -1354,7 +1354,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
val name = if (recipient.isGroupV2Recipient && invitingAdmin != null) {
invitingAdmin.getSearchName()
} else {
recipient.toShortString()
recipient.name
}
showSessionDialog {
@ -1420,7 +1420,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
title(R.string.blockUnblock)
text(
Phrase.from(context, R.string.blockUnblockName)
.put(NAME_KEY, recipient.toShortString())
.put(NAME_KEY, recipient.name)
.format()
)
dangerButton(R.string.blockUnblock, R.string.AccessibilityId_unblockConfirm) { viewModel.unblock() }
@ -1841,7 +1841,7 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate,
override fun sendMessage() {
val recipient = viewModel.recipient ?: return
if (recipient.isContactRecipient && recipient.isBlocked) {
BlockedDialog(recipient, this).show(supportFragmentManager, "Blocked Dialog")
BlockedDialog(recipient, viewModel.getUsername(recipient.address.serialize())).show(supportFragmentManager, "Blocked Dialog")
return
}
val sentMessageInfo = if (binding.inputBar.linkPreview != null || binding.inputBar.quote != null) {

@ -42,6 +42,7 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.StringSubstitutionConstants.DATE_KEY
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.getGroup
import org.session.libsession.utilities.recipients.MessageType
import org.session.libsession.utilities.recipients.Recipient
@ -82,6 +83,7 @@ class ConversationViewModel(
private val configFactory: ConfigFactory,
private val groupManagerV2: GroupManagerV2,
val legacyGroupDeprecationManager: LegacyGroupDeprecationManager,
private val usernameUtils: UsernameUtils
) : ViewModel() {
val showSendAfterApprovalText: Boolean
@ -1067,6 +1069,8 @@ class ConversationViewModel(
return true
}
fun getUsername(accountId: String) = usernameUtils.getContactNameWithAccountID(accountId)
@dagger.assisted.AssistedFactory
interface AssistedFactory {
fun create(threadId: Long, edKeyPair: KeyPair?): Factory
@ -1090,6 +1094,7 @@ class ConversationViewModel(
private val configFactory: ConfigFactory,
private val groupManagerV2: GroupManagerV2,
private val legacyGroupDeprecationManager: LegacyGroupDeprecationManager,
private val usernameUtils: UsernameUtils
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -1108,6 +1113,7 @@ class ConversationViewModel(
configFactory = configFactory,
groupManagerV2 = groupManagerV2,
legacyGroupDeprecationManager = legacyGroupDeprecationManager,
usernameUtils = usernameUtils
) as T
}
}

@ -16,16 +16,13 @@ import org.thoughtcrime.securesms.createSessionDialog
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() {
class BlockedDialog(private val recipient: Recipient, private val contactName: String) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = createSessionDialog {
val accountID = recipient.address.toString()
val name = MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(accountID)
val explanationCS = context.getSubbedCharSequence(R.string.blockUnblockName, NAME_KEY to name)
val explanationCS = context.getSubbedCharSequence(R.string.blockUnblockName, NAME_KEY to contactName)
val spannable = SpannableStringBuilder(explanationCS)
val startIndex = explanationCS.indexOf(name)
spannable.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + name.count(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
val startIndex = explanationCS.indexOf(contactName)
spannable.setSpan(StyleSpan(Typeface.BOLD), startIndex, startIndex + contactName.count(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
title(resources.getString(R.string.blockUnblock))
text(spannable)

@ -30,7 +30,7 @@ class AutoDownloadDialog(private val threadRecipient: Recipient,
title(getString(R.string.attachmentsAutoDownloadModalTitle))
val explanation = Phrase.from(context, R.string.attachmentsAutoDownloadModalDescription)
.put(CONVERSATION_NAME_KEY, threadRecipient.toShortString())
.put(CONVERSATION_NAME_KEY, threadRecipient.name)
.format()
text(explanation)

@ -296,7 +296,7 @@ object ConversationMenuHelper {
override fun onPostExecute(icon: IconCompat?) {
val name = Optional.fromNullable<String>(thread.name)
.or(Optional.fromNullable<String>(thread.profileName))
.or(thread.toShortString())
.or(thread.name)
val shortcutInfo = ShortcutInfoCompat.Builder(context, thread.address.serialize() + '-' + System.currentTimeMillis())
.setShortLabel(name)
.setIcon(icon)

@ -32,7 +32,6 @@ import network.loki.messenger.databinding.ViewEmojiReactionsBinding
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import network.loki.messenger.databinding.ViewstubVisibleMessageMarkerContainerBinding
import network.loki.messenger.libsession_util.getOrNull
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.contacts.Contact.ContactContext
import org.session.libsession.messaging.open_groups.OpenGroupApi
@ -41,6 +40,7 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.ThemeUtil.getThemedColor
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.getColorFromAttr
import org.session.libsession.utilities.modifyLayoutParams
@ -85,6 +85,7 @@ class VisibleMessageView : FrameLayout {
@Inject lateinit var mmsDb: MmsDatabase
@Inject lateinit var lastSentTimestampCache: LastSentTimestampCache
@Inject lateinit var configFactory: ConfigFactoryProtocol
@Inject lateinit var usernameUtils: UsernameUtils
private val binding = ViewVisibleMessageBinding.inflate(LayoutInflater.from(context), this, true)
@ -239,7 +240,7 @@ class VisibleMessageView : FrameLayout {
binding.senderNameTextView.isVisible = !message.isOutgoing && (isStartOfMessageCluster && (isGroupThread || snIsSelected))
val contactContext =
if (thread.isCommunityRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
binding.senderNameTextView.text = MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(
binding.senderNameTextView.text = usernameUtils.getContactNameWithAccountID(
contact = contact,
accountID = senderAccountID,
contactContext = contactContext,

@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.database
import android.content.Context
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.session.libsession.utilities.TextSecurePreferences
class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
@ -18,21 +17,4 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database
private val serverID = "server_id"
@JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($publicKey TEXT, $serverID TEXT, $displayName TEXT, PRIMARY KEY ($publicKey, $serverID));"
}
fun getDisplayName(publicKey: String): String? {
if (publicKey == TextSecurePreferences.getLocalNumber(context)) {
return TextSecurePreferences.getProfileName(context)
} else {
val database = databaseHelper.readableDatabase
val result = database.get(displayNameTable, "${Companion.publicKey} = ?", arrayOf( publicKey )) { cursor ->
cursor.getString(cursor.getColumnIndexOrThrow(displayName))
} ?: return null
val suffix = " (...${publicKey.substring(publicKey.count() - 8)})"
if (result.endsWith(suffix)) {
return result.substring(0..(result.count() - suffix.count()))
} else {
return result
}
}
}
}

@ -4,25 +4,18 @@ import android.content.Context
import android.net.Uri
import com.goterl.lazysodium.utils.KeyPair
import dagger.hilt.android.qualifiers.ApplicationContext
import java.security.MessageDigest
import javax.inject.Inject
import javax.inject.Singleton
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.Contact as LibSessionContact
import network.loki.messenger.libsession_util.util.ExpiryMode
import network.loki.messenger.libsession_util.util.GroupDisplayInfo
import network.loki.messenger.libsession_util.util.GroupInfo
import network.loki.messenger.libsession_util.util.GroupMember as LibSessionGroupMember
import network.loki.messenger.libsession_util.util.UserPic
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
@ -68,12 +61,12 @@ 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.UsernameUtils
import org.session.libsession.utilities.getGroup
import org.session.libsession.utilities.recipients.MessageType
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.recipients.Recipient.DisappearingState
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
@ -97,6 +90,11 @@ import org.thoughtcrime.securesms.groups.OpenGroupManager
import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.util.FilenameUtils
import org.thoughtcrime.securesms.util.SessionMetaProtocol
import java.security.MessageDigest
import javax.inject.Inject
import javax.inject.Singleton
import network.loki.messenger.libsession_util.util.Contact as LibSessionContact
import network.loki.messenger.libsession_util.util.GroupMember as LibSessionGroupMember
private const val TAG = "Storage"
@ -127,6 +125,7 @@ open class Storage @Inject constructor(
private val messageExpirationManager: SSKEnvironment.MessageExpirationManagerProtocol,
private val clock: SnodeClock,
private val preferences: TextSecurePreferences,
private val usernameUtils: UsernameUtils
) : Database(context, helper), StorageProtocol, ThreadDatabase.ConversationThreadUpdateListener {
init {
@ -230,7 +229,7 @@ open class Storage @Inject constructor(
override fun getUserED25519KeyPair(): KeyPair? { return KeyPairUtilities.getUserED25519KeyPair(context) }
override fun getUserProfile(): Profile {
val displayName = TextSecurePreferences.getProfileName(context)
val displayName = usernameUtils.getCurrentUsername()
val profileKey = ProfileKeyUtil.getProfileKey(context)
val profilePictureUrl = TextSecurePreferences.getProfilePictureURL(context)
return Profile(displayName, profileKey, profilePictureUrl)
@ -1247,21 +1246,6 @@ 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)
return getContactNameWithAccountID(contact, accountID, groupId, contactContext)
}
override fun getContactNameWithAccountID(contact: Contact?, accountID: String, groupId: AccountId?, contactContext: Contact.ContactContext): String {
// 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()
}

@ -49,7 +49,6 @@ import org.session.libsignal.utilities.Log;
import org.session.libsignal.utilities.Pair;
import org.session.libsignal.utilities.guava.Optional;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.contacts.ContactUtil;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.GroupThreadStatus;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
@ -62,7 +61,6 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.util.SessionMetaProtocol;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@ -798,10 +796,6 @@ public class ThreadDatabase extends Database {
private @NonNull String getFormattedBodyFor(@NonNull MessageRecord messageRecord) {
if (messageRecord.isMms()) {
MmsMessageRecord record = (MmsMessageRecord) messageRecord;
if (!record.getSharedContacts().isEmpty()) {
Contact contact = ((MmsMessageRecord)messageRecord).getSharedContacts().get(0);
return ContactUtil.getStringSummary(context, contact).toString();
}
String attachmentString = record.getSlideDeck().getBody();
if (!attachmentString.isEmpty()) {
if (!messageRecord.getBody().isEmpty()) {

@ -214,7 +214,7 @@ public class ThreadRecord extends DisplayRecord {
prefix = context.getString(R.string.you);
}
else if(lastMessage != null){
prefix = lastMessage.getIndividualRecipient().toShortString();
prefix = lastMessage.getIndividualRecipient().getName();
}
return Phrase.from(context.getString(R.string.messageSnippetGroup))

@ -43,6 +43,7 @@ import org.session.libsession.utilities.MutableUserConfigs
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UserConfigType
import org.session.libsession.utilities.UserConfigs
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.getGroup
import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.utilities.AccountId
@ -72,6 +73,7 @@ class ConfigFactory @Inject constructor(
private val textSecurePreferences: TextSecurePreferences,
private val clock: SnodeClock,
private val configToDatabaseSync: Lazy<ConfigToDatabaseSync>,
private val usernameUtils: Lazy<UsernameUtils>
) : ConfigFactoryProtocol {
companion object {
// This is a buffer period within which we will process messages which would result in a
@ -113,7 +115,9 @@ class ConfigFactory @Inject constructor(
userAccountId = userAccountId,
threadDb = threadDb,
configDatabase = configDatabase,
storage = storage.get()
storage = storage.get(),
textSecurePreferences = textSecurePreferences,
usernameUtils = usernameUtils.get()
)
}
}
@ -593,9 +597,14 @@ private fun MutableConversationVolatileConfig.initFrom(storage: StorageProtocol,
}
}
private fun MutableUserProfile.initFrom(storage: StorageProtocol) {
private fun MutableUserProfile.initFrom(storage: StorageProtocol,
usernameUtils: UsernameUtils,
textSecurePreferences: TextSecurePreferences
) {
val ownPublicKey = storage.getUserPublicKey() ?: return
val config = ConfigurationMessage.getCurrent(listOf()) ?: return
val displayName = usernameUtils.getCurrentUsername() ?: return
val profilePicture = textSecurePreferences.getProfilePictureURL()
val config = ConfigurationMessage.getCurrent(displayName, profilePicture, listOf()) ?: return
setName(config.displayName)
val picUrl = config.profilePicture
val picKey = config.profileKey
@ -652,6 +661,8 @@ private class UserConfigsImpl(
userEd25519SecKey: ByteArray,
private val userAccountId: AccountId,
private val configDatabase: ConfigDatabase,
private val textSecurePreferences: TextSecurePreferences,
private val usernameUtils: UsernameUtils,
storage: StorageProtocol,
threadDb: ThreadDatabase,
contactsDump: ByteArray? = configDatabase.retrieveConfigAndHashes(
@ -699,7 +710,7 @@ private class UserConfigsImpl(
}
if (userProfileDump == null) {
userProfile.initFrom(storage)
userProfile.initFrom(storage, usernameUtils, textSecurePreferences)
}
if (convoInfoDump == null) {

@ -1,11 +1,9 @@
package org.thoughtcrime.securesms.dependencies
import android.content.Context
import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@ -18,11 +16,11 @@ import org.session.libsession.messaging.groups.GroupScope
import org.session.libsession.messaging.groups.LegacyGroupDeprecationManager
import org.session.libsession.messaging.sending_receiving.pollers.LegacyClosedGroupPollerV2
import org.session.libsession.snode.SnodeClock
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UsernameUtils
import org.session.libsignal.database.LokiAPIDatabaseProtocol
import org.thoughtcrime.securesms.database.ConfigDatabase
import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.SessionContactDatabase
import org.thoughtcrime.securesms.util.UsernameUtilsImpl
import javax.inject.Named
import javax.inject.Singleton
@ -82,4 +80,16 @@ object SessionUtilModule {
fun provideLegacyGroupDeprecationManager(prefs: TextSecurePreferences): LegacyGroupDeprecationManager {
return LegacyGroupDeprecationManager(prefs)
}
@Provides
@Singleton
fun provideUsernameUtils(
prefs: TextSecurePreferences,
configFactory: ConfigFactory,
sessionContactDatabase: SessionContactDatabase,
): UsernameUtils = UsernameUtilsImpl(
prefs = prefs,
configFactory = configFactory,
sessionContactDatabase = sessionContactDatabase,
)
}

@ -20,6 +20,7 @@ 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.UsernameUtils
import org.session.libsignal.utilities.AccountId
import java.util.EnumSet
@ -28,6 +29,7 @@ abstract class BaseGroupMembersViewModel (
private val groupId: AccountId,
@ApplicationContext private val context: Context,
private val storage: StorageProtocol,
private val usernameUtils: UsernameUtils,
private val configFactory: ConfigFactoryProtocol
) : ViewModel() {
// Output: the source-of-truth group information. Other states are derived from this.
@ -77,7 +79,7 @@ abstract class BaseGroupMembersViewModel (
val name = if (isMyself) {
context.getString(R.string.you)
} else {
storage.getContactNameWithAccountID(member.accountId.hexString, groupId)
usernameUtils.getContactNameWithAccountID(member.accountId.hexString, groupId)
}
val highlightStatus = status in EnumSet.of(

@ -22,6 +22,7 @@ import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.groups.GroupInviteException
import org.session.libsession.messaging.groups.GroupManagerV2
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.UsernameUtils
import org.session.libsignal.utilities.AccountId
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.textSizeInBytes
@ -32,10 +33,11 @@ const val MAX_GROUP_NAME_BYTES = 100
class EditGroupViewModel @AssistedInject constructor(
@Assisted private val groupId: AccountId,
@ApplicationContext private val context: Context,
private val storage: StorageProtocol,
storage: StorageProtocol,
private val configFactory: ConfigFactoryProtocol,
private val groupManager: GroupManagerV2,
) : BaseGroupMembersViewModel(groupId, context, storage, configFactory) {
private val usernameUtils: UsernameUtils,
) : BaseGroupMembersViewModel(groupId, context, storage, usernameUtils, configFactory) {
// Input/Output state
private val mutableEditingName = MutableStateFlow<String?>(null)
@ -84,7 +86,7 @@ class EditGroupViewModel @AssistedInject constructor(
showLoading = false,
errorMessage = { err ->
if (err is GroupInviteException) {
err.format(context, storage).toString()
err.format(context, usernameUtils).toString()
} else {
null
}
@ -104,7 +106,7 @@ class EditGroupViewModel @AssistedInject constructor(
showLoading = false,
errorMessage = { err ->
if (err is GroupInviteException) {
err.format(context, storage).toString()
err.format(context, usernameUtils).toString()
} else {
null
}

@ -8,6 +8,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import org.session.libsession.database.StorageProtocol
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.UsernameUtils
import org.session.libsignal.utilities.AccountId
@ -16,8 +17,9 @@ class GroupMembersViewModel @AssistedInject constructor(
@Assisted private val groupId: AccountId,
@ApplicationContext context: Context,
storage: StorageProtocol,
configFactory: ConfigFactoryProtocol
) : BaseGroupMembersViewModel(groupId, context, storage, configFactory) {
configFactory: ConfigFactoryProtocol,
usernameUtils: UsernameUtils,
) : BaseGroupMembersViewModel(groupId, context, storage, usernameUtils, configFactory) {
@AssistedFactory
interface Factory {

@ -86,7 +86,6 @@ class ConversationView : LinearLayout {
binding.unreadMentionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
binding.unreadMentionIndicator.isVisible = (thread.unreadMentionCount != 0 && thread.recipient.address.isGroupOrCommunity)
val senderDisplayName = getTitle(thread.recipient)
?: thread.recipient.address.toString()
binding.conversationViewDisplayNameTextView.text = senderDisplayName
binding.timestampTextView.text = thread.date.takeIf { it != 0L }?.let { DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), it) }
val recipient = thread.recipient
@ -133,9 +132,9 @@ class ConversationView : LinearLayout {
binding.profilePictureView.recycle()
}
private fun getTitle(recipient: Recipient): String? = when {
private fun getTitle(recipient: Recipient): String = when {
recipient.isLocalNumber -> context.getString(R.string.noteToSelf)
else -> recipient.toShortString() // Internally uses the Contact API
else -> recipient.name // Internally uses the Contact API
}
// endregion
}

@ -406,7 +406,7 @@ class HomeActivity : ScreenLockActionBarActivity(),
private fun updateProfileButton() {
binding.profileButton.publicKey = publicKey
binding.profileButton.displayName = textSecurePreferences.getProfileName()
binding.profileButton.displayName = homeViewModel.getCurrentUsername()
binding.profileButton.recycle()
binding.profileButton.update()
}
@ -503,7 +503,7 @@ class HomeActivity : ScreenLockActionBarActivity(),
showSessionDialog {
title(R.string.block)
text(Phrase.from(context, R.string.blockDescription)
.put(NAME_KEY, thread.recipient.toShortString())
.put(NAME_KEY, thread.recipient.name)
.format())
dangerButton(R.string.block, R.string.AccessibilityId_blockConfirm) {
lifecycleScope.launch(Dispatchers.Default) {
@ -514,7 +514,7 @@ class HomeActivity : ScreenLockActionBarActivity(),
}
}
// Block confirmation toast added as per SS-64
val txt = Phrase.from(context, R.string.blockBlockedUser).put(NAME_KEY, thread.recipient.toShortString()).format().toString()
val txt = Phrase.from(context, R.string.blockBlockedUser).put(NAME_KEY, thread.recipient.name).format().toString()
Toast.makeText(context, txt, Toast.LENGTH_LONG).show()
}
cancelButton()
@ -524,7 +524,7 @@ class HomeActivity : ScreenLockActionBarActivity(),
private fun unblockConversation(thread: ThreadRecord) {
showSessionDialog {
title(R.string.blockUnblock)
text(Phrase.from(context, R.string.blockUnblockName).put(NAME_KEY, thread.recipient.toShortString()).format())
text(Phrase.from(context, R.string.blockUnblockName).put(NAME_KEY, thread.recipient.name).format())
dangerButton(R.string.blockUnblock, R.string.AccessibilityId_unblockConfirm) {
lifecycleScope.launch(Dispatchers.Default) {
storage.setBlocked(listOf(thread.recipient), false)
@ -673,7 +673,7 @@ class HomeActivity : ScreenLockActionBarActivity(),
else { // If this is a 1-on-1 conversation
title = getString(R.string.conversationsDelete)
message = Phrase.from(this, R.string.conversationsDeleteDescription)
.put(NAME_KEY, recipient.toShortString())
.put(NAME_KEY, recipient.name)
.format()
}
}

@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.home
import android.content.ContentResolver
import android.content.Context
import androidx.annotation.AttrRes
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asFlow
@ -28,6 +27,7 @@ import kotlinx.coroutines.flow.stateIn
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN
import org.session.libsession.utilities.ConfigUpdateNotification
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UsernameUtils
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.model.ThreadRecord
@ -42,7 +42,8 @@ class HomeViewModel @Inject constructor(
private val contentResolver: ContentResolver,
private val prefs: TextSecurePreferences,
private val typingStatusRepository: TypingStatusRepository,
private val configFactory: ConfigFactory
private val configFactory: ConfigFactory,
private val usernameUtils: UsernameUtils
) : ViewModel() {
// SharedFlow that emits whenever the user asks us to reload the conversation
private val manualReloadTrigger = MutableSharedFlow<Unit>(
@ -158,6 +159,8 @@ class HomeViewModel @Inject constructor(
}
}
fun getCurrentUsername() = usernameUtils.getCurrentUsernameWithAccountIdFallback()
companion object {
private const val CHANGE_NOTIFICATION_DEBOUNCE_MILLS = 100L
}

@ -132,7 +132,7 @@ fun ContentView.bindModel(query: String?, model: Message) = binding.apply {
val textSpannable = SpannableStringBuilder()
if (model.messageResult.conversationRecipient != model.messageResult.messageRecipient) {
// group chat, bind
val text = "${model.messageResult.messageRecipient.toShortString()}: "
val text = "${model.messageResult.messageRecipient.name}: "
textSpannable.append(text)
}
textSpannable.append(getHighlight(

@ -65,7 +65,7 @@ class MediaOverviewViewModel(
.shareIn(viewModelScope, SharingStarted.Eagerly, replay = 1)
val title: StateFlow<String> = recipient
.map { it.toShortString() }
.map { it.name }
.stateIn(viewModelScope, SharingStarted.Eagerly, "")
val mediaListState: StateFlow<MediaOverviewContent?> = recipient

@ -47,7 +47,7 @@ public class MediaPickerFolderFragment extends Fragment implements MediaPickerFo
public static @NonNull MediaPickerFolderFragment newInstance(@NonNull Recipient recipient) {
String name = Optional.fromNullable(recipient.getName())
.or(Optional.fromNullable(recipient.getProfileName()))
.or(recipient.toShortString());
.or(recipient.getName());
Bundle args = new Bundle();
args.putString(KEY_RECIPIENT_NAME, name);

@ -88,7 +88,7 @@ class MessageRequestsActivity : ScreenLockActionBarActivity(), ConversationClick
showSessionDialog {
title(R.string.block)
text(Phrase.from(context, R.string.blockDescription)
.put(NAME_KEY, thread.recipient.toShortString())
.put(NAME_KEY, thread.recipient.name)
.format())
dangerButton(R.string.block, R.string.AccessibilityId_blockConfirm) {
doBlock()

@ -42,7 +42,7 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
protected CharSequence getStyledMessage(@NonNull Recipient recipient, @Nullable CharSequence message) {
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(Util.getBoldedString(recipient.toShortString()));
builder.append(Util.getBoldedString(recipient.getName()));
builder.append(": ");
builder.append(message == null ? "" : message);

@ -45,7 +45,6 @@ import org.session.libsession.messaging.utilities.SodiumUtilities.blindedKeyPair
import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.ServiceUtil
import org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY
import org.session.libsession.utilities.TextSecurePreferences.Companion.getLocalNumber
import org.session.libsession.utilities.TextSecurePreferences.Companion.getNotificationPrivacy
import org.session.libsession.utilities.TextSecurePreferences.Companion.getRepeatAlertsCount
@ -58,7 +57,6 @@ import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.Util
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.contacts.ContactUtil
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities.highlightMentions
import org.thoughtcrime.securesms.crypto.KeyPairUtilities.getUserED25519KeyPair
import org.thoughtcrime.securesms.database.RecipientDatabase
@ -500,12 +498,7 @@ class DefaultMessageNotifier : MessageNotifier {
// ----- Note: All further cases assume we know the contact and that Session isn't locked -----
// If this is a notification about a multimedia message from a contact we know about..
} else if (record.isMms && !(record as MmsMessageRecord).sharedContacts.isEmpty()) {
val contact = (record as MmsMessageRecord).sharedContacts[0]
body = ContactUtil.getStringSummary(context, contact)
// If this is a notification about a multimedia message which contains no text but DOES contain a slide deck with at least one slide..
// If this is a notification about a multimedia message which contains no text but DOES contain a slide deck with at least one slide..
} else if (record.isMms && TextUtils.isEmpty(body) && !(record as MmsMessageRecord).slideDeck.slides.isEmpty()) {
slideDeck = (record as MediaMmsMessageRecord).slideDeck
body = SpanUtil.italic(slideDeck.body)

@ -40,7 +40,7 @@ class MultipleRecipientNotificationBuilder(context: Context, privacy: Notificati
}
fun setMostRecentSender(recipient: Recipient, threadRecipient: Recipient) {
var displayName = recipient.toShortString()
var displayName = recipient.name
if (threadRecipient.isGroupOrCommunityRecipient) {
displayName = getGroupDisplayName(recipient, threadRecipient.isCommunityRecipient)
}
@ -69,7 +69,7 @@ class MultipleRecipientNotificationBuilder(context: Context, privacy: Notificati
fun putStringExtra(key: String?, value: String?) { extras.putString(key, value) }
fun addMessageBody(sender: Recipient, threadRecipient: Recipient, body: CharSequence?) {
var displayName = sender.toShortString()
var displayName = sender.name
if (threadRecipient.isGroupOrCommunityRecipient) {
displayName = getGroupDisplayName(sender, threadRecipient.isCommunityRecipient)
}
@ -103,7 +103,7 @@ class MultipleRecipientNotificationBuilder(context: Context, privacy: Notificati
* @param openGroupRecipient whether in an open group context
*/
private fun getGroupDisplayName(recipient: Recipient, openGroupRecipient: Boolean): String {
return MessagingModuleConfiguration.shared.storage.getContactNameWithAccountID(
return MessagingModuleConfiguration.shared.usernameUtils.getContactNameWithAccountID(
accountID = recipient.address.serialize(),
contactContext = if (openGroupRecipient) Contact.ContactContext.OPEN_GROUP else Contact.ContactContext.REGULAR
)

@ -73,7 +73,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
setChannelId(channelId != null ? channelId : NotificationChannels.getMessagesChannel(context));
if (privacy.isDisplayContact()) {
setContentTitle(recipient.toShortString());
setContentTitle(recipient.getName());
if (recipient.getContactUri() != null) {
addPerson(recipient.getContactUri().toString());
@ -331,7 +331,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
* @param openGroupRecipient whether in an open group context
*/
private String getGroupDisplayName(Recipient recipient, boolean openGroupRecipient) {
return MessagingModuleConfiguration.getShared().getStorage().getContactNameWithAccountID(
return MessagingModuleConfiguration.getShared().getUsernameUtils().getContactNameWithAccountID(
recipient.getAddress().serialize(),
null,
openGroupRecipient ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR

@ -3,12 +3,11 @@ package org.thoughtcrime.securesms.onboarding.manager
import android.app.Application
import org.session.libsession.snode.SnodeModule
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UsernameUtils
import org.session.libsignal.database.LokiAPIDatabaseProtocol
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import org.thoughtcrime.securesms.util.VersionDataFetcher
import javax.inject.Inject
import javax.inject.Singleton
@ -17,7 +16,7 @@ import javax.inject.Singleton
class CreateAccountManager @Inject constructor(
private val application: Application,
private val prefs: TextSecurePreferences,
private val configFactory: ConfigFactory,
private val usernameUtils: UsernameUtils,
private val versionDataFetcher: VersionDataFetcher
) {
private val database: LokiAPIDatabaseProtocol
@ -43,9 +42,7 @@ class CreateAccountManager @Inject constructor(
prefs.setLocalNumber(userHexEncodedPublicKey)
prefs.setRestorationTime(0)
configFactory.withMutableUserConfigs {
it.userProfile.setName(displayName)
}
usernameUtils.saveCurrentUserName(displayName)
versionDataFetcher.startTimedVersionCheck()
}

@ -16,14 +16,12 @@ import kotlinx.coroutines.launch
import network.loki.messenger.R
import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol.Companion.NAME_PADDED_LENGTH
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsViewModel
import org.session.libsession.utilities.UsernameUtils
internal class PickDisplayNameViewModel(
private val loadFailed: Boolean,
private val prefs: TextSecurePreferences,
private val configFactory: ConfigFactory
private val usernameUtils: UsernameUtils,
): ViewModel() {
private val isCreateAccount = !loadFailed
@ -49,9 +47,7 @@ internal class PickDisplayNameViewModel(
viewModelScope.launch(Dispatchers.IO) {
if (loadFailed) {
prefs.setProfileName(displayName)
configFactory.withMutableUserConfigs {
it.userProfile.setName(displayName)
}
usernameUtils.saveCurrentUserName(displayName)
_events.emit(Event.LoadAccountComplete)
} else _events.emit(Event.CreateAccount(displayName))
}
@ -88,11 +84,11 @@ internal class PickDisplayNameViewModel(
class Factory @AssistedInject constructor(
@Assisted private val loadFailed: Boolean,
private val prefs: TextSecurePreferences,
private val configFactory: ConfigFactory
private val usernameUtils: UsernameUtils,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return PickDisplayNameViewModel(loadFailed, prefs, configFactory) as T
return PickDisplayNameViewModel(loadFailed, prefs, usernameUtils) as T
}
}
}

@ -25,8 +25,8 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.ProfileKeyUtil
import org.session.libsession.utilities.ProfilePictureUtilities
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.truncateIdForDisplay
import org.session.libsignal.utilities.ExternalStorageUtil.getImageDir
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.NoExternalStorageException
@ -47,6 +47,7 @@ class SettingsViewModel @Inject constructor(
private val prefs: TextSecurePreferences,
private val configFactory: ConfigFactory,
private val connectivity: InternetConnectivity,
private val usernameUtils: UsernameUtils
) : ViewModel() {
private val TAG = "SettingsViewModel"
@ -94,8 +95,7 @@ class SettingsViewModel @Inject constructor(
}
}
fun getDisplayName(): String =
prefs.getProfileName() ?: truncateIdForDisplay(hexEncodedPublicKey)
fun getDisplayName(): String = usernameUtils.getCurrentUsernameWithAccountIdFallback()
fun hasAvatar() = prefs.getProfileAvatarId() != 0
@ -246,9 +246,7 @@ class SettingsViewModel @Inject constructor(
}
fun updateName(displayName: String) {
configFactory.withMutableUserConfigs {
it.userProfile.setName(displayName)
}
usernameUtils.saveCurrentUserName(displayName)
}
fun permanentlyHidePassword() {

@ -44,7 +44,7 @@ public class DirectShareService extends ChooserTargetService {
while ((record = reader.getNext()) != null && results.size() < 10) {
Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false);
String name = recipient.toShortString();
String name = recipient.getName();
Bitmap avatar;

@ -0,0 +1,51 @@
package org.thoughtcrime.securesms.util
import network.loki.messenger.libsession_util.getOrNull
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.truncateIdForDisplay
import org.session.libsignal.utilities.AccountId
import org.thoughtcrime.securesms.database.SessionContactDatabase
import org.thoughtcrime.securesms.dependencies.ConfigFactory
class UsernameUtilsImpl(
private val prefs: TextSecurePreferences,
private val configFactory: ConfigFactory,
private val sessionContactDatabase: SessionContactDatabase,
): UsernameUtils {
override fun getCurrentUsernameWithAccountIdFallback(): String = prefs.getProfileName()
?: truncateIdForDisplay( prefs.getLocalNumber() ?: "")
override fun getCurrentUsername(): String? = prefs.getProfileName()
override fun saveCurrentUserName(name: String) {
configFactory.withMutableUserConfigs {
it.userProfile.setName(name)
}
}
override fun getContactNameWithAccountID(
accountID: String,
groupId: AccountId?,
contactContext: Contact.ContactContext
): String {
val contact = sessionContactDatabase.getContactWithAccountID(accountID)
return getContactNameWithAccountID(contact, accountID, groupId, contactContext)
}
override fun getContactNameWithAccountID(
contact: Contact?,
accountID: String,
groupId: AccountId?,
contactContext: Contact.ContactContext)
: String {
// 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)
}
}

@ -5,7 +5,7 @@ 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.session.libsession.utilities.UsernameUtils
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager
import org.webrtc.SurfaceViewRenderer
import javax.inject.Inject
@ -13,7 +13,7 @@ import javax.inject.Inject
@HiltViewModel
class CallViewModel @Inject constructor(
private val callManager: CallManager,
private val storage: StorageProtocol,
private val usernameUtils: UsernameUtils
): ViewModel() {
enum class State {
@ -69,7 +69,9 @@ class CallViewModel @Inject constructor(
val recipient get() = callManager.recipientEvents
val callStartTime: Long get() = callManager.callStartTime
fun getUserName(accountID: String) = storage.getContactNameWithAccountID(accountID)
fun getContactName(accountID: String) = usernameUtils.getContactNameWithAccountID(accountID)
fun getCurrentUsername() = usernameUtils.getCurrentUsernameWithAccountIdFallback()
fun swapVideos() {
callManager.swapVideos()

@ -61,7 +61,7 @@
<TextView
android:id="@+id/senderNameTextView"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
@ -71,6 +71,7 @@
android:paddingBottom="4dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@+id/messageInnerContainer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" />

@ -209,8 +209,6 @@ interface StorageProtocol {
// Contacts
fun getContactWithAccountID(accountID: String): Contact?
fun getContactNameWithAccountID(accountID: String, groupId: AccountId? = null, contactContext: Contact.ContactContext = Contact.ContactContext.REGULAR): String
fun getContactNameWithAccountID(contact: Contact?, 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?

@ -15,6 +15,7 @@ import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.Device
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.Toaster
import org.session.libsession.utilities.UsernameUtils
import org.session.libsignal.utilities.AccountId
class MessagingModuleConfiguration(
@ -31,6 +32,7 @@ class MessagingModuleConfiguration(
val preferences: TextSecurePreferences,
val legacyClosedGroupPollerV2: LegacyClosedGroupPollerV2,
val deprecationManager: LegacyGroupDeprecationManager,
val usernameUtils: UsernameUtils
) {
companion object {

@ -8,6 +8,7 @@ import org.session.libsession.utilities.StringSubstitutionConstants.COUNT_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.GROUP_NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.OTHER_NAME_KEY
import org.session.libsession.utilities.UsernameUtils
import org.session.libsession.utilities.truncateIdForDisplay
/**
@ -30,9 +31,9 @@ class GroupInviteException(
}
}
fun format(context: Context, storage: StorageProtocol): CharSequence {
fun format(context: Context, usernameUtils: UsernameUtils): CharSequence {
val getInviteeName = { accountId: String ->
storage.getContactNameWithAccountID(accountId)
usernameUtils.getContactNameWithAccountID(accountId)
}
val first = inviteeAccountIds.first().let(getInviteeName)

@ -105,7 +105,6 @@ class InviteContactsJob(val groupSessionId: String, val memberSessionIds: Array<
// assume job "success" even if we fail, the state of invites is tracked outside of this job
if (failures.isNotEmpty()) {
// show the failure toast
val storage = MessagingModuleConfiguration.shared.storage
val toaster = MessagingModuleConfiguration.shared.toaster
GroupInviteException(
@ -113,7 +112,8 @@ class InviteContactsJob(val groupSessionId: String, val memberSessionIds: Array<
inviteeAccountIds = failures.map { it.first },
groupName = groupName.orEmpty(),
underlying = failures.first().second.exceptionOrNull()!!,
).format(MessagingModuleConfiguration.shared.context, storage).let {
).format(MessagingModuleConfiguration.shared.context,
MessagingModuleConfiguration.shared.usernameUtils).let {
withContext(Dispatchers.Main) {
toaster.toast(it, Toast.LENGTH_LONG)
}

@ -6,7 +6,6 @@ import org.session.libsession.messaging.messages.copyExpiration
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.ProfileKeyUtil
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.crypto.ecc.DjbECPrivateKey
import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.crypto.ecc.ECKeyPair
@ -113,14 +112,12 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
companion object {
fun getCurrent(contacts: List<Contact>): ConfigurationMessage? {
fun getCurrent(displayName: String, profilePicture: String?, contacts: List<Contact>): ConfigurationMessage? {
val closedGroups = mutableListOf<ClosedGroup>()
val openGroups = mutableListOf<String>()
val sharedConfig = MessagingModuleConfiguration.shared
val storage = sharedConfig.storage
val context = sharedConfig.context
val displayName = TextSecurePreferences.getProfileName(context) ?: return null
val profilePicture = TextSecurePreferences.getProfilePictureURL(context)
val profileKey = ProfileKeyUtil.getProfileKey(context)
val groups = storage.getAllGroups(includeInactive = false)
for (group in groups) {

@ -33,9 +33,10 @@ object UpdateMessageBuilder {
val storage = MessagingModuleConfiguration.shared.storage
val usernameUtils = MessagingModuleConfiguration.shared.usernameUtils
private fun getGroupMemberName(memberId: String, groupId: AccountId? = null) =
storage.getContactNameWithAccountID(memberId, groupId)
usernameUtils.getContactNameWithAccountID(memberId, groupId)
@JvmStatic
fun buildGroupUpdateMessage(
@ -401,7 +402,7 @@ object UpdateMessageBuilder {
}
fun buildCallMessage(context: Context, type: CallMessageType, senderId: String): String {
val senderName = storage.getContactNameWithAccountID(senderId)
val senderName = usernameUtils.getContactNameWithAccountID(senderId)
return when (type) {
CALL_INCOMING -> Phrase.from(context, R.string.callsCalledYou).put(NAME_KEY, senderName)

@ -0,0 +1,25 @@
package org.session.libsession.utilities
import org.session.libsession.messaging.contacts.Contact
import org.session.libsignal.utilities.AccountId
interface UsernameUtils {
fun getCurrentUsernameWithAccountIdFallback(): String
fun getCurrentUsername(): String?
fun saveCurrentUserName(name: String)
fun getContactNameWithAccountID(
accountID: String,
groupId: AccountId? = null,
contactContext: Contact.ContactContext = Contact.ContactContext.REGULAR
): String
fun getContactNameWithAccountID(
contact: Contact?,
accountID: String,
groupId: AccountId? = null,
contactContext: Contact.ContactContext = Contact.ContactContext.REGULAR
): String
}

@ -44,6 +44,7 @@ import org.session.libsession.utilities.ListenableFutureTask;
import org.session.libsession.utilities.MaterialColor;
import org.session.libsession.utilities.ProfilePictureModifiedEvent;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.UsernameUtils;
import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.recipients.RecipientProvider.RecipientDetails;
import org.session.libsignal.utilities.Log;
@ -321,13 +322,13 @@ public class Recipient implements RecipientModifiedListener, Cloneable {
}
public synchronized @NonNull String getName() {
StorageProtocol storage = MessagingModuleConfiguration.getShared().getStorage();
UsernameUtils usernameUtils = MessagingModuleConfiguration.getShared().getUsernameUtils();
String accountID = this.address.toString();
if (isGroupOrCommunityRecipient()) {
if (this.name == null) {
List<String> names = new LinkedList<>();
for (Recipient recipient : participants) {
names.add(recipient.toShortString());
names.add(recipient.name);
}
return Util.join(names, ", ");
} else {
@ -335,9 +336,9 @@ public class Recipient implements RecipientModifiedListener, Cloneable {
}
} else if (isCommunityInboxRecipient()){
String inboxID = GroupUtil.getDecodedOpenGroupInboxAccountId(accountID);
return storage.getContactNameWithAccountID(inboxID, null, Contact.ContactContext.OPEN_GROUP);
return usernameUtils.getContactNameWithAccountID(inboxID, null, Contact.ContactContext.OPEN_GROUP);
} else {
return storage.getContactNameWithAccountID(accountID, null, Contact.ContactContext.REGULAR);
return usernameUtils.getContactNameWithAccountID(accountID, null, Contact.ContactContext.REGULAR);
}
}
@ -518,10 +519,6 @@ public class Recipient implements RecipientModifiedListener, Cloneable {
}
}
public synchronized String toShortString() {
return getName();
}
public synchronized @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted) {
return (new TransparentContactPhoto()).asDrawable(context, getColor().toAvatarColor(context), inverted);
}

Loading…
Cancel
Save