From c2c4c9f41a8aa6bfdfba0146f8b8cdd5985d6707 Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Thu, 3 Sep 2020 22:15:03 +1000 Subject: [PATCH 01/22] New avatar placeholder drawable generator. --- ...profile_picture_view_medium_background.xml | 2 - ...ile_picture_view_rss_medium_background.xml | 2 - .../profile_picture_view_small_background.xml | 2 - res/layout/activity_home.xml | 3 +- res/layout/activity_settings.xml | 3 +- res/layout/view_profile_picture.xml | 27 +----- res/values/colors.xml | 8 ++ .../conversation/ConversationItem.java | 1 + .../securesms/loki/activities/HomeActivity.kt | 14 ++-- .../loki/activities/SettingsActivity.kt | 5 +- .../loki/todo/AvatarPlaceholderGenerator.kt | 83 +++++++++++++++++++ .../securesms/loki/views/ConversationView.kt | 26 ++++-- .../loki/views/MentionCandidateView.kt | 1 + .../loki/views/ProfilePictureView.kt | 67 ++++++++++----- .../securesms/loki/views/UserView.kt | 3 + 15 files changed, 181 insertions(+), 66 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt diff --git a/res/drawable/profile_picture_view_medium_background.xml b/res/drawable/profile_picture_view_medium_background.xml index 287d6298e..143223ac1 100644 --- a/res/drawable/profile_picture_view_medium_background.xml +++ b/res/drawable/profile_picture_view_medium_background.xml @@ -6,6 +6,4 @@ - - \ No newline at end of file diff --git a/res/drawable/profile_picture_view_rss_medium_background.xml b/res/drawable/profile_picture_view_rss_medium_background.xml index b060c41b4..4d9a6a86d 100644 --- a/res/drawable/profile_picture_view_rss_medium_background.xml +++ b/res/drawable/profile_picture_view_rss_medium_background.xml @@ -6,6 +6,4 @@ - - \ No newline at end of file diff --git a/res/drawable/profile_picture_view_small_background.xml b/res/drawable/profile_picture_view_small_background.xml index 2f44fefe9..523316cf4 100644 --- a/res/drawable/profile_picture_view_small_background.xml +++ b/res/drawable/profile_picture_view_small_background.xml @@ -6,6 +6,4 @@ - - \ No newline at end of file diff --git a/res/layout/activity_home.xml b/res/layout/activity_home.xml index 13eb8bda5..b9dee3811 100644 --- a/res/layout/activity_home.xml +++ b/res/layout/activity_home.xml @@ -34,7 +34,8 @@ android:layout_height="@dimen/small_profile_picture_size" android:layout_alignParentLeft="true" android:layout_centerVertical="true" - android:layout_marginLeft="9dp" /> + android:layout_marginLeft="9dp" + android:foreground="@drawable/circle_touch_highlight_background"/> + android:layout_marginTop="@dimen/medium_spacing" + android:foreground="@drawable/circle_touch_highlight_background" /> - + android:layout_height="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - @@ -60,11 +51,6 @@ android:layout_height="match_parent" android:background="@drawable/profile_picture_view_medium_background" /> - - - - \ No newline at end of file diff --git a/res/values/colors.xml b/res/values/colors.xml index c9356d308..390c3be09 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -107,4 +107,12 @@ #121212 #171717 + + #18da80 + #ee8917 + #239edf + #c33fe9 + #83b433 + + diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index ca3d10db1..ed4f24d11 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -804,6 +804,7 @@ public class ConversationItem extends LinearLayout bodyBubble.setLayoutParams(layoutParams); if (profilePictureView == null) return; profilePictureView.setPublicKey(recipient.getAddress().toString()); + profilePictureView.setDisplayName(recipient.getName()); profilePictureView.setAdditionalPublicKey(null); profilePictureView.setRSSFeed(false); profilePictureView.setGlide(glideRequests); diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index 43e0647d2..af6f3b997 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.loki.activities import android.app.AlertDialog -import androidx.lifecycle.Observer import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -11,10 +10,6 @@ import android.net.Uri import android.os.AsyncTask import android.os.Bundle import android.os.Handler -import androidx.loader.app.LoaderManager -import androidx.loader.content.Loader -import androidx.localbroadcastmanager.content.LocalBroadcastManager -import androidx.recyclerview.widget.LinearLayoutManager import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan @@ -22,6 +17,11 @@ import android.util.DisplayMetrics import android.view.View import android.widget.RelativeLayout import android.widget.Toast +import androidx.lifecycle.Observer +import androidx.loader.app.LoaderManager +import androidx.loader.content.Loader +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.synthetic.main.activity_home.* import network.loki.messenger.R import org.thoughtcrime.securesms.ApplicationContext @@ -42,14 +42,13 @@ import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegat import org.thoughtcrime.securesms.loki.views.SeedReminderViewDelegate import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideRequests -import org.thoughtcrime.securesms.util.GroupUtil import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol -import org.whispersystems.signalservice.loki.protocol.shelved.multidevice.MultiDeviceProtocol import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol +import org.whispersystems.signalservice.loki.protocol.shelved.multidevice.MultiDeviceProtocol import org.whispersystems.signalservice.loki.protocol.shelved.syncmessages.SyncMessagesProtocol import org.whispersystems.signalservice.loki.utilities.toHexString @@ -98,6 +97,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe // Set up toolbar buttons profileButton.glide = glide profileButton.publicKey = publicKey + profileButton.displayName = TextSecurePreferences.getProfileName(this) profileButton.update() profileButton.setOnClickListener { openSettings() } pathStatusViewContainer.setOnClickListener { showPath() } diff --git a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt index 1a8811378..0d052d422 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt @@ -74,14 +74,17 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { setContentView(R.layout.activity_settings) + val origUserDisplayName = DatabaseFactory.getLokiUserDatabase(this).getDisplayName(hexEncodedPublicKey) + glide = GlideApp.with(this) profilePictureView.glide = glide profilePictureView.publicKey = hexEncodedPublicKey + profilePictureView.displayName = displayNameToBeUploaded profilePictureView.isLarge = true profilePictureView.update() profilePictureView.setOnClickListener { showEditProfilePictureUI() } ctnGroupNameSection.setOnClickListener { startActionMode(DisplayNameEditActionModeCallback()) } - btnGroupNameDisplay.text = DatabaseFactory.getLokiUserDatabase(this).getDisplayName(hexEncodedPublicKey) + btnGroupNameDisplay.text = origUserDisplayName publicKeyTextView.text = hexEncodedPublicKey copyButton.setOnClickListener { copyPublicKey() } shareButton.setOnClickListener { sharePublicKey() } diff --git a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt new file mode 100644 index 000000000..bca93db54 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt @@ -0,0 +1,83 @@ +package org.thoughtcrime.securesms.loki.todo + +import android.content.Context +import android.graphics.* +import android.graphics.drawable.BitmapDrawable +import android.text.TextPaint +import android.text.TextUtils +import androidx.annotation.ColorInt +import androidx.core.graphics.ColorUtils +import network.loki.messenger.R +import java.util.* + +object AvatarPlaceholderGenerator { + + private const val EMPTY_LABEL = "0"; + + private val tmpFloatArray = FloatArray(3) + + fun generate(context: Context, pixelSize: Int, hashString: String, displayName: String?): BitmapDrawable { + //TODO That should be replaced with a proper hash extraction code. + val hash: Long + val hexRegex = Regex("^[0-9A-Fa-f]+\$") + if (hashString.length >= 12 && hashString.matches(hexRegex)) { + hash = hashString.substring(0 until 12).toLong(16) + } else { + hash = hashString.toLong() + } + + // Do not cache color array, it may be different depends on the current theme. + val colorArray = context.resources.getIntArray(R.array.user_pic_placeholder_primary) + val colorPrimary = colorArray[(hash % colorArray.size).toInt()] + val colorSecondary = changeColorHueBy(colorPrimary, 16f) + + val labelText = when { + !TextUtils.isEmpty(displayName) -> extractLabel(displayName!!) + !TextUtils.isEmpty(hashString) -> extractLabel(hashString) + else -> EMPTY_LABEL + } + + val bitmap = Bitmap.createBitmap(pixelSize, pixelSize, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + + // Draw background/frame + val paint = Paint() + paint.isAntiAlias = true + paint.shader = LinearGradient(0f, 0f, 0f, pixelSize.toFloat(), + colorPrimary, + colorSecondary, + Shader.TileMode.REPEAT) + canvas.drawCircle(pixelSize.toFloat() / 2, pixelSize.toFloat() / 2, pixelSize.toFloat() / 2, paint) + + // Draw text + val textPaint = TextPaint() + textPaint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL) + textPaint.isAntiAlias = true + textPaint.textSize = pixelSize * 0.5f + textPaint.color = Color.WHITE + val areaRect = Rect(0, 0, pixelSize, pixelSize) + val textBounds = RectF(areaRect) + textBounds.right = textPaint.measureText(labelText) + textBounds.bottom = textPaint.descent() - textPaint.ascent() + textBounds.left += (areaRect.width() - textBounds.right) * 0.5f + textBounds.top += (areaRect.height() - textBounds.bottom) * 0.5f + canvas.drawText(labelText, textBounds.left, textBounds.top - textPaint.ascent(), textPaint) + + return BitmapDrawable(context.resources, bitmap) + } + + @ColorInt + private fun changeColorHueBy(@ColorInt color: Int, hueDelta: Float): Int { + val hslColor = tmpFloatArray + ColorUtils.colorToHSL(color, hslColor) + hslColor[0] = (hslColor[0] + hueDelta) % 360f + return ColorUtils.HSLToColor(hslColor) + } + + private fun extractLabel(content: String): String { + var content = content.trim() + if (content.isEmpty()) return EMPTY_LABEL + + return content.first().toString().toUpperCase(Locale.ROOT) + } +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt b/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt index 382ac63a8..181598b73 100644 --- a/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt @@ -2,12 +2,14 @@ package org.thoughtcrime.securesms.loki.views import android.content.Context import android.graphics.Typeface +import android.text.TextUtils import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import kotlinx.android.synthetic.main.view_conversation.view.* import network.loki.messenger.R +import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded import org.thoughtcrime.securesms.loki.utilities.MentionUtilities.highlightMentions @@ -58,22 +60,29 @@ class ConversationView : LinearLayout { if (thread.recipient.isGroupRecipient) { if ("Session Public Chat" == thread.recipient.name) { profilePictureView.publicKey = "" + profilePictureView.displayName = "" profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = true } else { - val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toMutableList() ?: mutableListOf() - users.remove(TextSecurePreferences.getLocalNumber(context)) + val userKeys = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toMutableList() ?: mutableListOf() + userKeys.remove(TextSecurePreferences.getLocalNumber(context)) val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context) if (masterPublicKey != null) { - users.remove(masterPublicKey) + userKeys.remove(masterPublicKey) } - val randomUsers = users.sorted() // Sort to provide a level of stability - profilePictureView.publicKey = randomUsers.getOrNull(0) ?: "" - profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: "" + + val sortedUserKeys = userKeys.sorted() // Sort to provide a level of stability + val userKey0 = sortedUserKeys.getOrNull(0) ?: "" + val userKey1 = sortedUserKeys.getOrNull(1) ?: "" + profilePictureView.publicKey = userKey0 + profilePictureView.displayName = getUserDisplayName(userKey0) + profilePictureView.additionalPublicKey = userKey1 + profilePictureView.additionalDisplayName = getUserDisplayName(userKey1) profilePictureView.isRSSFeed = thread.recipient.name == "Loki News" || thread.recipient.name == "Session Updates" } } else { profilePictureView.publicKey = thread.recipient.address.toString() + profilePictureView.displayName = thread.recipient.name profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false } @@ -103,5 +112,10 @@ class ConversationView : LinearLayout { else -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_check) } } + + private fun getUserDisplayName(publicKey: String?): String? { + if (TextUtils.isEmpty(publicKey)) return null + return DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey!!) + } // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt b/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt index 1e6a0d057..a9b62a5fd 100644 --- a/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt @@ -32,6 +32,7 @@ class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: private fun update() { btnGroupNameDisplay.text = mentionCandidate.displayName profilePictureView.publicKey = mentionCandidate.publicKey + profilePictureView.displayName = mentionCandidate.displayName profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false profilePictureView.glide = glide!! diff --git a/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt b/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt index 362f5ff35..d70f20fdc 100644 --- a/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt @@ -1,18 +1,18 @@ package org.thoughtcrime.securesms.loki.views import android.content.Context -import androidx.annotation.DimenRes import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.ImageView import android.widget.RelativeLayout +import androidx.annotation.DimenRes import com.bumptech.glide.load.engine.DiskCacheStrategy import kotlinx.android.synthetic.main.view_profile_picture.view.* import network.loki.messenger.R import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto import org.thoughtcrime.securesms.database.Address -import org.thoughtcrime.securesms.loki.todo.JazzIdenticonDrawable +import org.thoughtcrime.securesms.loki.todo.AvatarPlaceholderGenerator import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.TextSecurePreferences @@ -22,7 +22,9 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences class ProfilePictureView : RelativeLayout { lateinit var glide: GlideRequests var publicKey: String? = null + var displayName: String? = null var additionalPublicKey: String? = null + var additionalDisplayName: String? = null var isRSSFeed = false var isLarge = false @@ -58,28 +60,51 @@ class ProfilePictureView : RelativeLayout { singleModeImageViewContainer.visibility = if (additionalPublicKey == null && !isRSSFeed && !isLarge) View.VISIBLE else View.INVISIBLE largeSingleModeImageViewContainer.visibility = if (additionalPublicKey == null && !isRSSFeed && isLarge) View.VISIBLE else View.INVISIBLE rssImageView.visibility = if (isRSSFeed) View.VISIBLE else View.INVISIBLE - fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, @DimenRes sizeID: Int) { - glide.clear(imageView) - if (hexEncodedPublicKey.isNotEmpty()) { - val recipient = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false); - val signalProfilePicture = recipient.contactPhoto - if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0" && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "") { - glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView) - } else { - val size = resources.getDimensionPixelSize(sizeID) - val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context) - val hepk = if (recipient.isLocalNumber && masterHexEncodedPublicKey != null) masterHexEncodedPublicKey else hexEncodedPublicKey - val jazzIcon = JazzIdenticonDrawable(size, size, hepk) - glide.load(jazzIcon).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView) - } + + setProfilePictureIfNeeded( + doubleModeImageView1, + publicKey, + displayName, + R.dimen.small_profile_picture_size) + setProfilePictureIfNeeded( + doubleModeImageView2, + additionalPublicKey ?: "", + additionalDisplayName, + R.dimen.small_profile_picture_size) + setProfilePictureIfNeeded( + singleModeImageView, + publicKey, + displayName, + R.dimen.medium_profile_picture_size) + setProfilePictureIfNeeded( + largeSingleModeImageView, + publicKey, + displayName, + R.dimen.large_profile_picture_size) + } + + private fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, displayName: String?, @DimenRes sizeResId: Int) { + glide.clear(imageView) + if (hexEncodedPublicKey.isNotEmpty()) { + val recipient = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false); + val signalProfilePicture = recipient.contactPhoto + if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0" && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "") { + glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView) } else { - imageView.setImageDrawable(null) + val sizePx = resources.getDimensionPixelSize(sizeResId) + val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context) + val hepk = if (recipient.isLocalNumber && masterHexEncodedPublicKey != null) masterHexEncodedPublicKey else hexEncodedPublicKey +// val jazzIcon = JazzIdenticonDrawable(size, size, hepk) + glide.load(AvatarPlaceholderGenerator.generate( + context, + sizePx, + hepk, + displayName + )).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView) } + } else { + imageView.setImageDrawable(null) } - setProfilePictureIfNeeded(doubleModeImageView1, publicKey, R.dimen.small_profile_picture_size) - setProfilePictureIfNeeded(doubleModeImageView2, additionalPublicKey ?: "", R.dimen.small_profile_picture_size) - setProfilePictureIfNeeded(singleModeImageView, publicKey, R.dimen.medium_profile_picture_size) - setProfilePictureIfNeeded(largeSingleModeImageView, publicKey, R.dimen.large_profile_picture_size) } // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/views/UserView.kt b/src/org/thoughtcrime/securesms/loki/views/UserView.kt index 9619a9038..2347f07cc 100644 --- a/src/org/thoughtcrime/securesms/loki/views/UserView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/UserView.kt @@ -51,6 +51,7 @@ class UserView : LinearLayout { if (user.isGroupRecipient) { if ("Session Public Chat" == user.name || user.address.isRSSFeed) { profilePictureView.publicKey = "" + profilePictureView.displayName = null profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = true } else { @@ -58,11 +59,13 @@ class UserView : LinearLayout { val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf() val randomUsers = users.sorted() // Sort to provide a level of stability profilePictureView.publicKey = randomUsers.getOrNull(0) ?: "" + profilePictureView.displayName = null profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: "" profilePictureView.isRSSFeed = false } } else { profilePictureView.publicKey = address + profilePictureView.displayName = null profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false } From 3e82c8f9ea288bdd3815a2b8bc1065972d16272c Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Fri, 4 Sep 2020 00:08:34 +1000 Subject: [PATCH 02/22] User pic placeholder colors tweaks. Use proper username for settings activity placeholder. --- res/values/colors.xml | 7 +++---- .../securesms/loki/activities/SettingsActivity.kt | 2 +- .../securesms/loki/todo/AvatarPlaceholderGenerator.kt | 8 +++----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/res/values/colors.xml b/res/values/colors.xml index 390c3be09..caaccd140 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -108,11 +108,10 @@ #171717 - #18da80 - #ee8917 + #2bca81 + #ee7117 #239edf - #c33fe9 - #83b433 + #bb35e9 diff --git a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt index 0d052d422..efd7836ff 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt @@ -79,7 +79,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { glide = GlideApp.with(this) profilePictureView.glide = glide profilePictureView.publicKey = hexEncodedPublicKey - profilePictureView.displayName = displayNameToBeUploaded + profilePictureView.displayName = origUserDisplayName profilePictureView.isLarge = true profilePictureView.update() profilePictureView.setOnClickListener { showEditProfilePictureUI() } diff --git a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt index bca93db54..d79f736c8 100644 --- a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt +++ b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt @@ -29,7 +29,7 @@ object AvatarPlaceholderGenerator { // Do not cache color array, it may be different depends on the current theme. val colorArray = context.resources.getIntArray(R.array.user_pic_placeholder_primary) val colorPrimary = colorArray[(hash % colorArray.size).toInt()] - val colorSecondary = changeColorHueBy(colorPrimary, 16f) + val colorSecondary = changeColorHueBy(colorPrimary, 12f) val labelText = when { !TextUtils.isEmpty(displayName) -> extractLabel(displayName!!) @@ -41,8 +41,7 @@ object AvatarPlaceholderGenerator { val canvas = Canvas(bitmap) // Draw background/frame - val paint = Paint() - paint.isAntiAlias = true + val paint = Paint(Paint.ANTI_ALIAS_FLAG) paint.shader = LinearGradient(0f, 0f, 0f, pixelSize.toFloat(), colorPrimary, colorSecondary, @@ -50,9 +49,8 @@ object AvatarPlaceholderGenerator { canvas.drawCircle(pixelSize.toFloat() / 2, pixelSize.toFloat() / 2, pixelSize.toFloat() / 2, paint) // Draw text - val textPaint = TextPaint() + val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG) textPaint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL) - textPaint.isAntiAlias = true textPaint.textSize = pixelSize * 0.5f textPaint.color = Color.WHITE val areaRect = Rect(0, 0, pixelSize, pixelSize) From 8f2fc3ab74c0e31c3880b04660eb543841eee009 Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Fri, 4 Sep 2020 00:30:14 +1000 Subject: [PATCH 03/22] New user avatar placeholder for message received notification. --- .../SingleRecipientNotificationBuilder.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java index bc5f695a3..29fab4e4c 100644 --- a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java +++ b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java @@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.loki.todo.AvatarPlaceholderGenerator; import org.thoughtcrime.securesms.loki.utilities.NotificationUtilities; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.GlideApp; @@ -80,9 +81,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil addPerson(recipient.getContactUri().toString()); } - ContactPhoto contactPhoto = recipient.getContactPhoto(); - FallbackContactPhoto fallbackContactPhoto = recipient.getFallbackContactPhoto(); - + ContactPhoto contactPhoto = recipient.getContactPhoto(); if (contactPhoto != null) { try { setLargeIcon(GlideApp.with(context.getApplicationContext()) @@ -94,10 +93,10 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil .get()); } catch (InterruptedException | ExecutionException e) { Log.w(TAG, e); - setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getColor().toConversationColor(context))); + setLargeIcon(obtainAvatarPlaceholderDrawable(context, recipient)); } } else { - setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getColor().toConversationColor(context))); + setLargeIcon(obtainAvatarPlaceholderDrawable(context, recipient)); } } else { @@ -321,4 +320,14 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil return content; } + private static Drawable obtainAvatarPlaceholderDrawable(Context context, Recipient recipient) { + //TODO Copied from ProfilePictureView#setProfilePictureIfNeeded + // Refactor this code to use the same recipient placeholder generator method across the app. + String publicKey = recipient.getAddress().serialize(); + String hepk = (recipient.isLocalNumber() && publicKey != null) + ? TextSecurePreferences.getMasterHexEncodedPublicKey(context) + : publicKey; + String displayName = recipient.getName(); + return AvatarPlaceholderGenerator.INSTANCE.generate(context, 128, hepk, displayName); + } } From ad67f478c8ce5c6464dcb03705c9237aadc2493b Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Fri, 4 Sep 2020 01:00:06 +1000 Subject: [PATCH 04/22] Use proper radix for the public key number conversion. --- .../securesms/loki/todo/AvatarPlaceholderGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt index d79f736c8..4596efd20 100644 --- a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt +++ b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt @@ -23,7 +23,7 @@ object AvatarPlaceholderGenerator { if (hashString.length >= 12 && hashString.matches(hexRegex)) { hash = hashString.substring(0 until 12).toLong(16) } else { - hash = hashString.toLong() + hash = hashString.toLong(16) } // Do not cache color array, it may be different depends on the current theme. From f9b11665878eb92ce96a9406d393ca4c78a1835b Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Fri, 4 Sep 2020 11:51:12 +1000 Subject: [PATCH 05/22] Do not parse public key to a number if it's shorter than 12 chars. --- .../securesms/loki/todo/AvatarPlaceholderGenerator.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt index 4596efd20..9cea1618f 100644 --- a/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt +++ b/src/org/thoughtcrime/securesms/loki/todo/AvatarPlaceholderGenerator.kt @@ -19,11 +19,10 @@ object AvatarPlaceholderGenerator { fun generate(context: Context, pixelSize: Int, hashString: String, displayName: String?): BitmapDrawable { //TODO That should be replaced with a proper hash extraction code. val hash: Long - val hexRegex = Regex("^[0-9A-Fa-f]+\$") - if (hashString.length >= 12 && hashString.matches(hexRegex)) { + if (hashString.length >= 12 && hashString.matches(Regex("^[0-9A-Fa-f]+\$"))) { hash = hashString.substring(0 until 12).toLong(16) } else { - hash = hashString.toLong(16) + hash = 0 } // Do not cache color array, it may be different depends on the current theme. From b14cf5fcf86bdd6b3dc2e3b31e391079414fc536 Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Fri, 4 Sep 2020 13:57:20 +1000 Subject: [PATCH 06/22] Fixed there's no label for the UserView's avatar placeholder. --- .../securesms/loki/views/UserView.kt | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/views/UserView.kt b/src/org/thoughtcrime/securesms/loki/views/UserView.kt index 2347f07cc..3b1108226 100644 --- a/src/org/thoughtcrime/securesms/loki/views/UserView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/UserView.kt @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.loki.views import android.content.Context +import android.text.TextUtils import android.util.AttributeSet import android.view.LayoutInflater import android.view.View @@ -8,6 +9,7 @@ import android.widget.LinearLayout import kotlinx.android.synthetic.main.view_conversation.view.profilePictureView import kotlinx.android.synthetic.main.view_user.view.* import network.loki.messenger.R +import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.recipients.Recipient @@ -56,16 +58,20 @@ class UserView : LinearLayout { profilePictureView.isRSSFeed = true } else { val threadID = GroupManager.getThreadIDFromGroupID(address, context) - val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf() - val randomUsers = users.sorted() // Sort to provide a level of stability - profilePictureView.publicKey = randomUsers.getOrNull(0) ?: "" - profilePictureView.displayName = null - profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: "" + val userKeys = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf() + val sortedUserKeys = userKeys.sorted() // Sort to provide a level of stability + val userKey0 = sortedUserKeys.getOrNull(0) ?: "" + val userKey1 = sortedUserKeys.getOrNull(1) ?: "" + + profilePictureView.publicKey = userKey0 + profilePictureView.displayName = getUserDisplayName(userKey0) + profilePictureView.additionalPublicKey = userKey1 + profilePictureView.additionalDisplayName = getUserDisplayName(userKey1) profilePictureView.isRSSFeed = false } } else { profilePictureView.publicKey = address - profilePictureView.displayName = null + profilePictureView.displayName = getUserDisplayName(address) profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false } @@ -87,5 +93,10 @@ class UserView : LinearLayout { } } } + + private fun getUserDisplayName(publicKey: String?): String? { + if (TextUtils.isEmpty(publicKey)) return null + return DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey!!) + } // endregion } \ No newline at end of file From be788738dcc718a7f4524ef8db37e214e5bf0248 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 7 Sep 2020 10:57:25 +1000 Subject: [PATCH 07/22] Implement user details sheet --- .../fragment_conversation_bottom_sheet.xml | 11 +++- .../fragment_user_details_bottom_sheet.xml | 50 +++++++++++++++++++ res/values/strings.xml | 1 + .../securesms/loki/activities/HomeActivity.kt | 6 +++ .../dialogs/ConversationOptionsBottomSheet.kt | 13 +++-- .../loki/dialogs/UserDetailsBottomSheet.kt | 19 +++++++ 6 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 res/layout/fragment_user_details_bottom_sheet.xml create mode 100644 src/org/thoughtcrime/securesms/loki/dialogs/UserDetailsBottomSheet.kt diff --git a/res/layout/fragment_conversation_bottom_sheet.xml b/res/layout/fragment_conversation_bottom_sheet.xml index 274417418..4cd470857 100644 --- a/res/layout/fragment_conversation_bottom_sheet.xml +++ b/res/layout/fragment_conversation_bottom_sheet.xml @@ -9,13 +9,20 @@ app:behavior_hideable="true" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> + + + tools:visibility="visible" /> + tools:visibility="visible" /> + + + + + + + + +