refactor: use simpler way to generate closed group profile pictures, limit the getConversation call in MentionManagerUtilities.kt to 200 to improve link-through performance to v2 conversation activity. fix notify type not being preloaded into settings

This commit is contained in:
jubb 2021-08-03 13:35:38 +10:00
parent dd01b2968f
commit 9b48d5d203
7 changed files with 80 additions and 73 deletions

View File

@ -142,7 +142,7 @@ dependencies {
testImplementation 'org.robolectric:shadows-multidex:4.2' testImplementation 'org.robolectric:shadows-multidex:4.2'
} }
def canonicalVersionCode = 214 def canonicalVersionCode = 215
def canonicalVersionName = "1.11.7" def canonicalVersionName = "1.11.7"
def postFixSize = 10 def postFixSize = 10

View File

@ -53,17 +53,15 @@ class ProfilePictureView : RelativeLayout {
return recipient.isOpenGroupRecipient && recipient.groupAvatarId != null return recipient.isOpenGroupRecipient && recipient.groupAvatarId != null
} }
if (recipient.isGroupRecipient && !isOpenGroupWithProfilePicture(recipient)) { if (recipient.isGroupRecipient && !isOpenGroupWithProfilePicture(recipient)) {
val users = MentionsManager.userPublicKeyCache[threadID]?.toMutableList() ?: mutableListOf() val members = DatabaseFactory.getGroupDatabase(context)
users.remove(TextSecurePreferences.getLocalNumber(context)) .getGroupMemberAddresses(recipient.address.toGroupString(), true)
val randomUsers = users.sorted().toMutableList() // Sort to provide a level of stability .sorted()
if (users.count() == 1) { .take(2)
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!! .toMutableList()
randomUsers.add(0, userPublicKey) // Ensure the current user is at the back visually val pk = members.getOrNull(0)?.serialize() ?: ""
}
val pk = randomUsers.getOrNull(0) ?: ""
publicKey = pk publicKey = pk
displayName = getUserDisplayName(pk) displayName = getUserDisplayName(pk)
val apk = randomUsers.getOrNull(1) ?: "" val apk = members.getOrNull(1)?.serialize() ?: ""
additionalPublicKey = apk additionalPublicKey = apk
additionalDisplayName = getUserDisplayName(apk) additionalDisplayName = getUserDisplayName(apk)
} else { } else {

View File

@ -13,13 +13,13 @@ object MentionManagerUtilities {
if (MentionsManager.userPublicKeyCache[threadID] != null) return if (MentionsManager.userPublicKeyCache[threadID] != null) return
val result = mutableSetOf<String>() val result = mutableSetOf<String>()
val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID) val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID) ?: return
if (recipient != null && recipient.address.isClosedGroup) { if (recipient.address.isClosedGroup) {
val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.address.toGroupString(), false).map { it.address.serialize() } val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.address.toGroupString(), false).map { it.address.serialize() }
result.addAll(members) result.addAll(members)
} else { } else {
val messageDatabase = DatabaseFactory.getMmsSmsDatabase(context) val messageDatabase = DatabaseFactory.getMmsSmsDatabase(context)
val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID)) val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID, 0, 200))
var record: MessageRecord? = reader.next var record: MessageRecord? = reader.next
while (record != null) { while (record != null) {
result.add(record.individualRecipient.address.serialize()) result.add(record.individualRecipient.address.serialize())

View File

@ -14,6 +14,7 @@ import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteDatabase;
import org.session.libsession.utilities.TextSecurePreferences;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.BitmapUtil;
@ -155,6 +156,20 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
return recipients; return recipients;
} }
public @NonNull List<Address> getGroupMemberAddresses(String groupId, boolean includeSelf) {
List<Address> members = getCurrentMembers(groupId, false);
if (!includeSelf) {
String ownNumber = TextSecurePreferences.getLocalNumber(context);
if (ownNumber == null) return members;
Address ownAddress = Address.fromSerialized(ownNumber);
int indexOfSelf = members.indexOf(ownAddress);
if (indexOfSelf >= 0) {
members.remove(indexOfSelf);
}
}
return members;
}
public @NonNull List<Recipient> getGroupZombieMembers(String groupId) { public @NonNull List<Recipient> getGroupZombieMembers(String groupId) {
List<Address> members = getCurrentZombieMembers(groupId); List<Address> members = getCurrentZombieMembers(groupId);
List<Recipient> recipients = new LinkedList<>(); List<Recipient> recipients = new LinkedList<>();

View File

@ -651,7 +651,7 @@ public class ThreadDatabase extends Database {
groupRecord = Optional.absent(); groupRecord = Optional.absent();
} }
Recipient recipient = Recipient.from(context, address, settings, groupRecord, false); Recipient recipient = Recipient.from(context, address, settings, groupRecord, true);
String body = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET)); String body = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET));
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE)); long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT)); long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));

View File

@ -12,11 +12,8 @@ import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.view_conversation.view.* import kotlinx.android.synthetic.main.view_conversation.view.*
import kotlinx.android.synthetic.main.view_profile_picture.view.*
import kotlinx.coroutines.*
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities.highlightMentions import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities.highlightMentions
import org.thoughtcrime.securesms.database.RecipientDatabase import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.database.model.ThreadRecord
@ -42,63 +39,58 @@ class ConversationView : LinearLayout {
// region Updating // region Updating
fun bind(thread: ThreadRecord, isTyping: Boolean, glide: GlideRequests) { fun bind(thread: ThreadRecord, isTyping: Boolean, glide: GlideRequests) {
this.thread = thread this.thread = thread
profilePictureView.glide = glide val unreadCount = thread.unreadCount
if (thread.recipient.isBlocked) {
accentView.setBackgroundResource(R.color.destructive)
accentView.visibility = View.VISIBLE
} else {
accentView.setBackgroundResource(R.color.accent)
accentView.visibility = if (unreadCount > 0) View.VISIBLE else View.INVISIBLE
}
val formattedUnreadCount = if (unreadCount < 100) unreadCount.toString() else "99+"
unreadCountTextView.text = formattedUnreadCount
val textSize = if (unreadCount < 100) 12.0f else 9.0f
unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
unreadCountTextView.setTypeface(Typeface.DEFAULT, if (unreadCount < 100) Typeface.BOLD else Typeface.NORMAL)
unreadCountIndicator.isVisible = (unreadCount != 0)
val senderDisplayName = getUserDisplayName(thread.recipient)
?: thread.recipient.address.toString()
conversationViewDisplayNameTextView.text = senderDisplayName
timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
val recipient = thread.recipient
muteIndicatorImageView.isVisible = recipient.isMuted || recipient.notifyType != RecipientDatabase.NOTIFY_TYPE_ALL
val drawableRes = if (recipient.isMuted || recipient.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) {
R.drawable.ic_outline_notifications_off_24
} else {
R.drawable.ic_notifications_mentions
}
muteIndicatorImageView.setImageResource(drawableRes)
val rawSnippet = thread.getDisplayBody(context)
val snippet = highlightMentions(rawSnippet, thread.threadId, context)
snippetTextView.text = snippet
snippetTextView.typeface = if (unreadCount > 0) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
if (isTyping) {
typingIndicatorView.startAnimation()
} else {
typingIndicatorView.stopAnimation()
}
typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
statusIndicatorImageView.visibility = View.VISIBLE
when {
!thread.isOutgoing -> statusIndicatorImageView.visibility = View.GONE
thread.isFailed -> {
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_error)?.mutate()
drawable?.setTint(ContextCompat.getColor(context, R.color.destructive))
statusIndicatorImageView.setImageDrawable(drawable)
}
thread.isPending -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)
thread.isRead -> statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check)
else -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_check)
}
post { post {
val unreadCount = thread.unreadCount profilePictureView.glide = glide
if (thread.recipient.isBlocked) { profilePictureView.update(thread.recipient, thread.threadId)
accentView.setBackgroundResource(R.color.destructive)
accentView.visibility = View.VISIBLE
} else {
accentView.setBackgroundResource(R.color.accent)
accentView.visibility = if (unreadCount > 0) View.VISIBLE else View.INVISIBLE
}
val formattedUnreadCount = if (unreadCount < 100) unreadCount.toString() else "99+"
unreadCountTextView.text = formattedUnreadCount
val textSize = if (unreadCount < 100) 12.0f else 9.0f
unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
unreadCountTextView.setTypeface(Typeface.DEFAULT, if (unreadCount < 100) Typeface.BOLD else Typeface.NORMAL)
unreadCountIndicator.isVisible = (unreadCount != 0)
val senderDisplayName = getUserDisplayName(thread.recipient)
?: thread.recipient.address.toString()
conversationViewDisplayNameTextView.text = senderDisplayName
timestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), thread.date)
val recipient = thread.recipient
muteIndicatorImageView.isVisible = recipient.isMuted || recipient.notifyType != RecipientDatabase.NOTIFY_TYPE_ALL
val drawableRes = if (recipient.isMuted || recipient.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) {
R.drawable.ic_outline_notifications_off_24
} else {
R.drawable.ic_notifications_mentions
}
muteIndicatorImageView.setImageResource(drawableRes)
val rawSnippet = thread.getDisplayBody(context)
val snippet = highlightMentions(rawSnippet, thread.threadId, context)
snippetTextView.text = snippet
snippetTextView.typeface = if (unreadCount > 0) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
if (isTyping) {
typingIndicatorView.startAnimation()
} else {
typingIndicatorView.stopAnimation()
}
typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
statusIndicatorImageView.visibility = View.VISIBLE
when {
!thread.isOutgoing -> statusIndicatorImageView.visibility = View.GONE
thread.isFailed -> {
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_error)?.mutate()
drawable?.setTint(ContextCompat.getColor(context, R.color.destructive))
statusIndicatorImageView.setImageDrawable(drawable)
}
thread.isPending -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)
thread.isRead -> statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check)
else -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_check)
}
GlobalScope.launch(Dispatchers.IO) {
populateUserPublicKeyCacheIfNeeded(thread.threadId, context) // FIXME: This is a bad place to do this
withContext(Dispatchers.Main) {
profilePictureView.update(thread.recipient, thread.threadId)
}
}
} }
} }

View File

@ -153,6 +153,7 @@ public class Recipient implements RecipientModifiedListener {
this.profileSharing = stale.profileSharing; this.profileSharing = stale.profileSharing;
this.unidentifiedAccessMode = stale.unidentifiedAccessMode; this.unidentifiedAccessMode = stale.unidentifiedAccessMode;
this.forceSmsSelection = stale.forceSmsSelection; this.forceSmsSelection = stale.forceSmsSelection;
this.notifyType = stale.notifyType;
this.participants.clear(); this.participants.clear();
this.participants.addAll(stale.participants); this.participants.addAll(stale.participants);
@ -180,6 +181,7 @@ public class Recipient implements RecipientModifiedListener {
this.profileSharing = details.get().profileSharing; this.profileSharing = details.get().profileSharing;
this.unidentifiedAccessMode = details.get().unidentifiedAccessMode; this.unidentifiedAccessMode = details.get().unidentifiedAccessMode;
this.forceSmsSelection = details.get().forceSmsSelection; this.forceSmsSelection = details.get().forceSmsSelection;
this.notifyType = details.get().notifyType;
this.participants.clear(); this.participants.clear();
this.participants.addAll(details.get().participants); this.participants.addAll(details.get().participants);