From 7de2f0f4602b9700463562dbf8ee6267846428c3 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 19 Mar 2024 13:52:06 -0300 Subject: [PATCH] Add nickname and notes fields to the RecipientTable. --- .../securesms/database/RecipientTable.kt | 19 ++++++++++++-- .../database/RecipientTableCursorUtil.kt | 4 ++- .../helpers/SignalDatabaseMigrations.kt | 6 +++-- ...ddNicknameAndNoteFieldsToRecipientTable.kt | 22 ++++++++++++++++ .../database/model/RecipientRecord.kt | 4 ++- .../securesms/recipients/Recipient.java | 26 ++++++++++++++++++- .../securesms/recipients/RecipientDetails.kt | 12 ++++++--- .../database/RecipientDatabaseTestUtils.kt | 4 ++- 8 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt index 3af6daba79..f073e2ce7e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -186,6 +186,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da const val PHONE_NUMBER_SHARING = "phone_number_sharing" const val PHONE_NUMBER_DISCOVERABLE = "phone_number_discoverable" const val PNI_SIGNATURE_VERIFIED = "pni_signature_verified" + const val NICKNAME_GIVEN_NAME = "nickname_given_name" + const val NICKNAME_FAMILY_NAME = "nickname_family_name" + const val NICKNAME_JOINED_NAME = "nickname_joined_name" + const val NOTE = "note" const val SEARCH_PROFILE_NAME = "search_signal_profile" const val SORT_NAME = "sort_name" @@ -254,7 +258,11 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da $REPORTING_TOKEN BLOB DEFAULT NULL, $PHONE_NUMBER_SHARING INTEGER DEFAULT ${PhoneNumberSharingState.UNKNOWN.id}, $PHONE_NUMBER_DISCOVERABLE INTEGER DEFAULT ${PhoneNumberDiscoverableState.UNKNOWN.id}, - $PNI_SIGNATURE_VERIFIED INTEGER DEFAULT 0 + $PNI_SIGNATURE_VERIFIED INTEGER DEFAULT 0, + $NICKNAME_GIVEN_NAME TEXT DEFAULT NULL, + $NICKNAME_FAMILY_NAME TEXT DEFAULT NULL, + $NICKNAME_JOINED_NAME TEXT DEFAULT NULL, + $NOTE TEXT DEFAULT NULL ) """ @@ -314,7 +322,10 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da BADGES, NEEDS_PNI_SIGNATURE, REPORTING_TOKEN, - PHONE_NUMBER_SHARING + PHONE_NUMBER_SHARING, + NICKNAME_GIVEN_NAME, + NICKNAME_FAMILY_NAME, + NOTE ) private val ID_PROJECTION = arrayOf(ID) @@ -335,6 +346,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da """ LOWER( COALESCE( + NULLIF($NICKNAME_JOINED_NAME, ''), + NULLIF($NICKNAME_GIVEN_NAME, ''), NULLIF($SYSTEM_JOINED_NAME, ''), NULLIF($SYSTEM_GIVEN_NAME, ''), NULLIF($PROFILE_JOINED_NAME, ''), @@ -374,6 +387,8 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da """ REPLACE( COALESCE( + NULLIF($NICKNAME_JOINED_NAME, ''), + NULLIF($NICKNAME_GIVEN_NAME, ''), NULLIF($SYSTEM_JOINED_NAME, ''), NULLIF($SYSTEM_GIVEN_NAME, ''), NULLIF($PROFILE_JOINED_NAME, ''), diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTableCursorUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTableCursorUtil.kt index edc29af53e..b86b6e6ec2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTableCursorUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTableCursorUtil.kt @@ -165,7 +165,9 @@ object RecipientTableCursorUtil { needsPniSignature = cursor.requireBoolean(RecipientTable.NEEDS_PNI_SIGNATURE), hiddenState = Recipient.HiddenState.deserialize(cursor.requireInt(RecipientTable.HIDDEN)), callLinkRoomId = cursor.requireString(RecipientTable.CALL_LINK_ROOM_ID)?.let { CallLinkRoomId.DatabaseSerializer.deserialize(it) }, - phoneNumberSharing = cursor.requireInt(RecipientTable.PHONE_NUMBER_SHARING).let { RecipientTable.PhoneNumberSharingState.fromId(it) } + phoneNumberSharing = cursor.requireInt(RecipientTable.PHONE_NUMBER_SHARING).let { RecipientTable.PhoneNumberSharingState.fromId(it) }, + nickname = ProfileName.fromParts(cursor.requireString(RecipientTable.NICKNAME_GIVEN_NAME), cursor.requireString(RecipientTable.NICKNAME_FAMILY_NAME)), + note = cursor.requireString(RecipientTable.NOTE) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index cdddc48cb3..747b810686 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -80,6 +80,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V219_PniPreKeyStore import org.thoughtcrime.securesms.database.helpers.migration.V220_PreKeyConstraints import org.thoughtcrime.securesms.database.helpers.migration.V221_AddReadColumnToCallEventsTable import org.thoughtcrime.securesms.database.helpers.migration.V222_DataHashRefactor +import org.thoughtcrime.securesms.database.helpers.migration.V223_AddNicknameAndNoteFieldsToRecipientTable /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -162,10 +163,11 @@ object SignalDatabaseMigrations { 219 to V219_PniPreKeyStores, 220 to V220_PreKeyConstraints, 221 to V221_AddReadColumnToCallEventsTable, - 222 to V222_DataHashRefactor + 222 to V222_DataHashRefactor, + 223 to V223_AddNicknameAndNoteFieldsToRecipientTable ) - const val DATABASE_VERSION = 222 + const val DATABASE_VERSION = 223 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt new file mode 100644 index 0000000000..4dbfea54c9 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V223_AddNicknameAndNoteFieldsToRecipientTable.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Adds necessary fields to the recipeints table for the nickname & notes feature. + */ +@Suppress("ClassName") +object V223_AddNicknameAndNoteFieldsToRecipientTable : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE recipient ADD COLUMN nickname_given_name TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE recipient ADD COLUMN nickname_family_name TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE recipient ADD COLUMN nickname_joined_name TEXT DEFAULT NULL") + db.execSQL("ALTER TABLE recipient ADD COLUMN note TEXT DEFAULT NULL") + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt index 3830afc481..72ddce8e81 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/RecipientRecord.kt @@ -78,7 +78,9 @@ data class RecipientRecord( val needsPniSignature: Boolean, val hiddenState: Recipient.HiddenState, val callLinkRoomId: CallLinkRoomId?, - val phoneNumberSharing: PhoneNumberSharingState + val phoneNumberSharing: PhoneNumberSharingState, + val nickname: ProfileName, + val note: String? ) { fun e164Only(): Boolean { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index 04782bf699..6570a5d880 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -139,6 +139,8 @@ public class Recipient { private final CallLinkRoomId callLinkRoomId; private final Optional groupRecord; private final PhoneNumberSharingState phoneNumberSharing; + private final ProfileName nickname; + private final String note; /** * Returns a {@link LiveRecipient}, which contains a {@link Recipient} that may or may not be @@ -429,6 +431,8 @@ public class Recipient { this.callLinkRoomId = null; this.groupRecord = Optional.empty(); this.phoneNumberSharing = PhoneNumberSharingState.UNKNOWN; + this.nickname = ProfileName.EMPTY; + this.note = null; } public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) { @@ -485,6 +489,8 @@ public class Recipient { this.callLinkRoomId = details.callLinkRoomId; this.groupRecord = details.groupRecord; this.phoneNumberSharing = details.phoneNumberSharing; + this.nickname = details.nickname; + this.note = details.note; } public @NonNull RecipientId getId() { @@ -549,6 +555,7 @@ public class Recipient { */ public boolean hasAUserSetDisplayName(@NonNull Context context) { return !TextUtils.isEmpty(getGroupName(context)) || + !TextUtils.isEmpty(getNickname().toString()) || !TextUtils.isEmpty(systemContactName) || !TextUtils.isEmpty(getProfileName().toString()); } @@ -577,6 +584,10 @@ public class Recipient { private @Nullable String getNameFromLocalData(@NonNull Context context) { String name = getGroupName(context); + if (Util.isEmpty(name)) { + name = getNickname().toString(); + } + if (Util.isEmpty(name)) { name = systemContactName; } @@ -600,6 +611,11 @@ public class Recipient { String name = isSelf ? getProfileName().toString() : getGroupName(context); name = StringUtil.isolateBidi(name); + if (Util.isEmpty(name)) { + name = isSelf ? getGroupName(context) : getNickname().toString(); + name = StringUtil.isolateBidi(name); + } + if (Util.isEmpty(name)) { name = isSelf ? getGroupName(context) : systemContactName; name = StringUtil.isolateBidi(name); @@ -627,6 +643,7 @@ public class Recipient { public @NonNull String getShortDisplayName(@NonNull Context context) { String name = Util.getFirstNonEmpty(getGroupName(context), + getNickname().getGivenName(), getSystemProfileName().getGivenName(), getProfileName().getGivenName(), getUsername().orElse(null), @@ -825,6 +842,10 @@ public class Recipient { return requireSmsAddress(); } + public @NonNull ProfileName getNickname() { + return nickname; + } + public @NonNull ProfileName getProfileName() { return signalProfileName; } @@ -960,6 +981,7 @@ public class Recipient { else if (isGroupInternal()) return fallbackPhotoProvider.getPhotoForGroup(); else if (isGroup()) return fallbackPhotoProvider.getPhotoForGroup(); else if (!TextUtils.isEmpty(groupName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(groupName, targetSize); + else if (!nickname.isEmpty()) return fallbackPhotoProvider.getPhotoForRecipientWithName(nickname.toString(), targetSize); else if (!TextUtils.isEmpty(systemContactName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(systemContactName, targetSize); else if (!signalProfileName.isEmpty()) return fallbackPhotoProvider.getPhotoForRecipientWithName(signalProfileName.toString(), targetSize); else return fallbackPhotoProvider.getPhotoForRecipientWithoutName(); @@ -1394,7 +1416,9 @@ public class Recipient { Objects.equals(badges, other.badges) && isActiveGroup == other.isActiveGroup && Objects.equals(callLinkRoomId, other.callLinkRoomId) && - phoneNumberSharing == other.phoneNumberSharing; + phoneNumberSharing == other.phoneNumberSharing && + Objects.equals(nickname, other.nickname) && + Objects.equals(note, other.note); } private static boolean allContentsAreTheSame(@NonNull List a, @NonNull List b) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.kt b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.kt index 4244012a2e..cb592b57a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.kt @@ -81,7 +81,9 @@ class RecipientDetails private constructor( @JvmField val needsPniSignature: Boolean, @JvmField val callLinkRoomId: CallLinkRoomId?, @JvmField val groupRecord: Optional, - @JvmField val phoneNumberSharing: PhoneNumberSharingState + @JvmField val phoneNumberSharing: PhoneNumberSharingState, + @JvmField val nickname: ProfileName, + @JvmField val note: String? ) { @VisibleForTesting @@ -146,7 +148,9 @@ class RecipientDetails private constructor( needsPniSignature = record.needsPniSignature, callLinkRoomId = record.callLinkRoomId, groupRecord = groupRecord, - phoneNumberSharing = record.phoneNumberSharing + phoneNumberSharing = record.phoneNumberSharing, + nickname = record.nickname, + note = record.note ) companion object { @@ -275,7 +279,9 @@ class RecipientDetails private constructor( isActiveGroup = false, callLinkRoomId = null, groupRecord = Optional.empty(), - phoneNumberSharing = PhoneNumberSharingState.UNKNOWN + phoneNumberSharing = PhoneNumberSharingState.UNKNOWN, + nickname = ProfileName.EMPTY, + note = "" ) } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt b/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt index 2dac3b81cb..ab08f477e3 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/RecipientDatabaseTestUtils.kt @@ -142,7 +142,9 @@ object RecipientDatabaseTestUtils { needsPniSignature = false, hiddenState = Recipient.HiddenState.NOT_HIDDEN, callLinkRoomId = null, - phoneNumberSharing = RecipientTable.PhoneNumberSharingState.UNKNOWN + phoneNumberSharing = RecipientTable.PhoneNumberSharingState.UNKNOWN, + nickname = ProfileName.EMPTY, + note = null ), participantIds = participants, isReleaseChannel = isReleaseChannel,