From 6e3188f1dfb3857b3b9ab49d9cbd4cfcdcd474ab Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 19 Nov 2024 13:55:28 +0100 Subject: [PATCH 01/12] display email address of guest users for moderators Signed-off-by: Marcel Hibbe --- .../talk/adapters/items/ParticipantItem.kt | 14 +++++++++++--- .../conversationinfo/ConversationInfoActivity.kt | 2 +- .../talk/models/json/participants/Participant.kt | 3 +++ .../rv_item_conversation_info_participant.xml | 1 - 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt index 9126cd6b3..bfe4d801f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt @@ -26,11 +26,13 @@ import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.extensions.loadGuestAvatar import com.nextcloud.talk.extensions.loadMailAvatar import com.nextcloud.talk.extensions.loadUserAvatar +import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.models.json.participants.Participant.InCallFlags import com.nextcloud.talk.models.json.status.StatusType import com.nextcloud.talk.ui.StatusDrawable import com.nextcloud.talk.ui.theme.ViewThemeUtils +import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils.convertDpToPixel import eu.davidea.flexibleadapter.FlexibleAdapter @@ -45,7 +47,7 @@ class ParticipantItem( val model: Participant, private val user: User, private val viewThemeUtils: ViewThemeUtils, - private val roomToken: String + private val conversation: ConversationModel ) : AbstractFlexibleItem(), IFilterable { var isOnline = true override fun equals(o: Any?): Boolean { @@ -128,7 +130,13 @@ class ParticipantItem( Participant.ParticipantType.GUEST -> { userType = sharedApplication!!.getString(R.string.nc_guest) if (model.calculatedActorType == Participant.ActorType.EMAILS) { - userType = sharedApplication!!.getString(R.string.nc_email) + userType = sharedApplication!!.getString(R.string.nc_guest) + } + + if (model.invitedActorId?.isNotEmpty() == true && + ConversationUtils.isParticipantOwnerOrModerator(conversation)) { + holder.binding.conversationInfoStatusMessage.text = model.invitedActorId + alignUsernameVertical(holder, 0f) } } @@ -218,7 +226,7 @@ class ParticipantItem( holder.binding.avatarView.loadFederatedUserAvatar( user, user.baseUrl!!, - roomToken, + conversation.token, model.actorId!!, darkTheme, true, diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index b491094ab..d6f72f3cb 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -568,7 +568,7 @@ class ConversationInfoActivity : for (i in participants.indices) { participant = participants[i] - userItem = ParticipantItem(this, participant, conversationUser, viewThemeUtils, conversationToken) + userItem = ParticipantItem(this, participant, conversationUser, viewThemeUtils, conversation!!) if (participant.sessionId != null) { userItem.isOnline = !participant.sessionId.equals("0") } else { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt b/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt index 11b92d61e..ae8b374c9 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt @@ -72,6 +72,9 @@ data class Participant( @JsonField(name = ["statusMessage"]) var statusMessage: String? = null, + @JsonField(name = ["invitedActorId"]) + var invitedActorId: String? = null, + var selected: Boolean = false ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' diff --git a/app/src/main/res/layout/rv_item_conversation_info_participant.xml b/app/src/main/res/layout/rv_item_conversation_info_participant.xml index a72288131..94520135e 100644 --- a/app/src/main/res/layout/rv_item_conversation_info_participant.xml +++ b/app/src/main/res/layout/rv_item_conversation_info_participant.xml @@ -66,7 +66,6 @@ android:ellipsize="end" android:maxLines="3" android:textAlignment="viewStart" - android:textAppearance="?android:attr/textAppearanceListItem" android:textColor="?android:attr/textColorSecondary" android:layout_marginEnd="@dimen/side_margin" app:layout_constraintBottom_toBottomOf="parent" From 8a3f779fdc1c3e6cdec312daa69f16ef4119978b Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 19 Nov 2024 17:18:18 +0100 Subject: [PATCH 02/12] show initials avatar for email guests if displayname is set Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/adapters/items/ParticipantItem.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt index bfe4d801f..1a680128b 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt @@ -206,7 +206,13 @@ class ParticipantItem( } Participant.ActorType.EMAILS -> { - holder.binding.avatarView.loadMailAvatar(viewThemeUtils) + model.displayName?.let { + if (TextUtils.isEmpty(it)) { + holder.binding.avatarView.loadMailAvatar(viewThemeUtils) + } else { + holder.binding.avatarView.loadGuestAvatar(user, it, false) + } + } } Participant.ActorType.USERS -> { From 6ede78eb0991765f7ad696c14e1030fde91cff6b Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 19 Nov 2024 18:09:04 +0100 Subject: [PATCH 03/12] remove additional information from autocomplete objectId would be some long random string for email guests. displaying them would not make sense. It's also not done on web. Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt index 4fffdd120..5d7a8b2d8 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt @@ -109,7 +109,6 @@ class MentionAutocompleteItem( ) } else { holder.binding.nameText.text = displayName - holder.binding.secondaryText.text = "@$objectId" } var avatarId = objectId when (source) { From ca9e2d49325a29125b13c79173cb3b1218e1f3c8 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 19 Nov 2024 18:23:37 +0100 Subject: [PATCH 04/12] enable to set mention chip for email guests Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/utils/message/MessageUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt index fa3a3b93c..4c6b3c07e 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt @@ -107,7 +107,7 @@ class MessageUtils(val context: Context) { val individualHashMap = message.messageParameters!![key] if (individualHashMap != null) { when (individualHashMap["type"]) { - "user", "guest", "call", "user-group" -> { + "user", "guest", "call", "user-group", "email" -> { val chip = if (individualHashMap["id"] == message.activeUser!!.userId) { R.xml.chip_you } else { From 02d0a65909069f0a240dee03bfcab9d74ed5dbd1 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 19 Nov 2024 21:57:05 +0100 Subject: [PATCH 05/12] enable to set mention chip for email guests 2 Signed-off-by: Marcel Hibbe --- .../main/java/com/nextcloud/talk/chat/MessageInputFragment.kt | 3 ++- .../main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt | 2 +- app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index fcbe494c9..87f7a8fd2 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -856,7 +856,8 @@ class MessageInputFragment : Fragment() { val shouldQuote = mentionId.contains(" ") || mentionId.contains("@") || mentionId.startsWith("guest/") || - mentionId.startsWith("group/") + mentionId.startsWith("group/") || + mentionId.startsWith("email/") if (shouldQuote) { mentionId = "\"" + mentionId + "\"" } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt index c8f2da614..6a7a70f31 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt @@ -29,7 +29,7 @@ class ChatUtils { if (individualHashMap != null) { val type = individualHashMap["type"] - resultMessage = if (type == "user" || type == "guest" || type == "call") { + resultMessage = if (type == "user" || type == "guest" || type == "call" || type == "email") { resultMessage?.replace("{$key}", "@" + individualHashMap["name"]) } else if (type == "geo-location") { individualHashMap["name"] diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt index 532f830bf..cb8268cab 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt @@ -176,7 +176,7 @@ object DisplayUtils { chip.setBounds(0, 0, chip.intrinsicWidth, chip.intrinsicHeight) if (!isCallOrGroup) { var url = getUrlForAvatar(conversationUser.baseUrl, id, false) - if ("guests" == type || "guest" == type) { + if ("guests" == type || "guest" == type || "email" == type) { url = getUrlForGuestAvatar( conversationUser.baseUrl, label.toString(), true ) From d95c1c605f749aef3d4555dd8dd022434f7f012a Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 20 Nov 2024 14:37:31 +0100 Subject: [PATCH 06/12] set guest avatar for guests and emailguests in autocomplete knowing if a guest did not change it's name is not possible at this point, so we also show the letter "G" if it's name is guest Signed-off-by: Marcel Hibbe --- .../talk/adapters/items/MentionAutocompleteItem.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt index 5d7a8b2d8..3e3ba686f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.kt @@ -17,6 +17,7 @@ import com.nextcloud.talk.R import com.nextcloud.talk.adapters.items.ParticipantItem.ParticipantItemViewHolder import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.extensions.loadFederatedUserAvatar +import com.nextcloud.talk.extensions.loadGuestAvatar import com.nextcloud.talk.extensions.loadUserAvatar import com.nextcloud.talk.models.json.mention.Mention import com.nextcloud.talk.models.json.status.StatusType @@ -146,9 +147,9 @@ class MentionAutocompleteItem( ) } - SOURCE_GUESTS -> { - run { avatarId = displayName } - run { holder.binding.avatarView.loadUserAvatar(currentUser, avatarId!!, true, false) } + SOURCE_GUESTS, SOURCE_EMAILS -> { + avatarId = displayName + holder.binding.avatarView.loadGuestAvatar(currentUser, avatarId!!, false) } else -> { @@ -217,6 +218,7 @@ class MentionAutocompleteItem( const val SOURCE_CALLS = "calls" const val SOURCE_GUESTS = "guests" const val SOURCE_GROUPS = "groups" + const val SOURCE_EMAILS = "emails" const val SOURCE_FEDERATION = "federated_users" } } From b71218973ecb1b83cf6b69c2789faf256b811049 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Wed, 20 Nov 2024 17:49:27 +0100 Subject: [PATCH 07/12] show simple person icon when conversation-info when guest did not set any name However this is only possible for the conversation info. In other parts, the info if a guest changed the name or not is not available (like in the chat or in autocomplete) Signed-off-by: Marcel Hibbe --- .../talk/adapters/items/ParticipantItem.kt | 23 ++++++------------- .../talk/extensions/ImageViewExtensions.kt | 9 ++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt index 1a680128b..dad6ed7ed 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt @@ -21,10 +21,10 @@ import com.nextcloud.talk.adapters.items.ParticipantItem.ParticipantItemViewHold import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.RvItemConversationInfoParticipantBinding +import com.nextcloud.talk.extensions.loadDefaultAvatar import com.nextcloud.talk.extensions.loadDefaultGroupCallAvatar import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.extensions.loadGuestAvatar -import com.nextcloud.talk.extensions.loadMailAvatar import com.nextcloud.talk.extensions.loadUserAvatar import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.participants.Participant @@ -173,6 +173,7 @@ class ParticipantItem( } } + @SuppressLint("StringFormatInvalid") private fun showCallIcons(holder: ParticipantItemViewHolder) { val resources = sharedApplication!!.resources val inCallFlag = model.inCall @@ -205,26 +206,16 @@ class ParticipantItem( holder.binding.avatarView.loadDefaultGroupCallAvatar(viewThemeUtils) } - Participant.ActorType.EMAILS -> { - model.displayName?.let { - if (TextUtils.isEmpty(it)) { - holder.binding.avatarView.loadMailAvatar(viewThemeUtils) - } else { - holder.binding.avatarView.loadGuestAvatar(user, it, false) - } - } - } - Participant.ActorType.USERS -> { holder.binding.avatarView.loadUserAvatar(user, model.calculatedActorId!!, true, false) } - Participant.ActorType.GUESTS -> { - var displayName: String? = sharedApplication!!.resources.getString(R.string.nc_guest) - if (!TextUtils.isEmpty(model.displayName)) { - displayName = model.displayName + Participant.ActorType.GUESTS, Participant.ActorType.EMAILS -> { + if (model.displayName.isNullOrEmpty()) { + holder.binding.avatarView.loadDefaultAvatar(viewThemeUtils) + } else { + holder.binding.avatarView.loadGuestAvatar(user, model.displayName!!, false) } - holder.binding.avatarView.loadGuestAvatar(user, displayName!!, false) } Participant.ActorType.FEDERATED -> { diff --git a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt index ef43da5f8..137ead73c 100644 --- a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt @@ -320,6 +320,15 @@ fun ImageView.loadDefaultGroupCallAvatar(viewThemeUtils: ViewThemeUtils): io.rea return loadUserAvatar(data) } +fun ImageView.loadDefaultAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable { + val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.account_circle_96dp) as Any + } else { + R.drawable.account_circle_96dp + } + return loadUserAvatar(data) +} + fun ImageView.loadDefaultPublicCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable { val data: Any = viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_link) as Any return loadUserAvatar(data) From cb3614da34a7e24149b1d67242e8d243b6494dd3 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 21 Nov 2024 12:33:40 +0100 Subject: [PATCH 08/12] remove android version check Signed-off-by: Marcel Hibbe --- .../com/nextcloud/talk/extensions/ImageViewExtensions.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt index 137ead73c..335a81d6f 100644 --- a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt @@ -321,11 +321,7 @@ fun ImageView.loadDefaultGroupCallAvatar(viewThemeUtils: ViewThemeUtils): io.rea } fun ImageView.loadDefaultAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable { - val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.account_circle_96dp) as Any - } else { - R.drawable.account_circle_96dp - } + val data: Any = viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.account_circle_96dp) as Any return loadUserAvatar(data) } From c75cf2fe209dfb0b95f73a44e8bd46b92f34fe86 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 21 Nov 2024 12:57:09 +0100 Subject: [PATCH 09/12] add grey avatar with first letter of email-guest Signed-off-by: Marcel Hibbe --- .../talk/adapters/items/ParticipantItem.kt | 6 ++- .../talk/extensions/ImageViewExtensions.kt | 49 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt index dad6ed7ed..4b58041ab 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/ParticipantItem.kt @@ -24,7 +24,7 @@ import com.nextcloud.talk.databinding.RvItemConversationInfoParticipantBinding import com.nextcloud.talk.extensions.loadDefaultAvatar import com.nextcloud.talk.extensions.loadDefaultGroupCallAvatar import com.nextcloud.talk.extensions.loadFederatedUserAvatar -import com.nextcloud.talk.extensions.loadGuestAvatar +import com.nextcloud.talk.extensions.loadFirstLetterAvatar import com.nextcloud.talk.extensions.loadUserAvatar import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.participants.Participant @@ -214,7 +214,9 @@ class ParticipantItem( if (model.displayName.isNullOrEmpty()) { holder.binding.avatarView.loadDefaultAvatar(viewThemeUtils) } else { - holder.binding.avatarView.loadGuestAvatar(user, model.displayName!!, false) + holder.binding.avatarView.loadFirstLetterAvatar( + model.displayName!!.first().toString() + ) } } diff --git a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt index 335a81d6f..1d70a986c 100644 --- a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt @@ -10,12 +10,19 @@ package com.nextcloud.talk.extensions +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.util.Log import android.widget.ImageView import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat import coil.annotation.ExperimentalCoilApi import coil.imageLoader import coil.load @@ -35,6 +42,7 @@ import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.TextDrawable +import java.util.Locale private const val ROUNDING_PIXEL = 16f private const val TAG = "ImageViewExtensions" @@ -297,6 +305,21 @@ fun ImageView.loadNoteToSelfAvatar(): io.reactivex.disposables.Disposable { ) } +fun ImageView.loadFirstLetterAvatar(letter: String): io.reactivex.disposables.Disposable { + val layers = arrayOfNulls(2) + layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background) + layers[1] = createTextDrawable(context, letter.uppercase(Locale.ROOT)) + + val layerDrawable = LayerDrawable(layers) + val data: Any = layerDrawable + + return DisposableWrapper( + load(data) { + transformations(CircleCropTransformation()) + } + ) +} + fun ImageView.loadChangelogBotAvatar(): io.reactivex.disposables.Disposable { return loadSystemAvatar() } @@ -355,6 +378,32 @@ fun ImageView.loadGuestAvatar(baseUrl: String, name: String, big: Boolean): io.r ) } +@Suppress("MagicNumber") +private fun createTextDrawable(context: Context, letter: String): Drawable { + val size = 100 + val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + + val paint = Paint().apply { + color = ResourcesCompat.getColor(context.resources, R.color.grey_600, null) + style = Paint.Style.FILL + } + canvas.drawRect(0f, 0f, size.toFloat(), size.toFloat(), paint) + + val textPaint = Paint().apply { + color = Color.WHITE + textSize = size / 2f + isAntiAlias = true + textAlign = Paint.Align.CENTER + } + + val xPos = size / 2f + val yPos = (canvas.height / 2 - (textPaint.descent() + textPaint.ascent()) / 2) + canvas.drawText(letter.take(1), xPos, yPos, textPaint) + + return BitmapDrawable(context.resources, bitmap) +} + private class DisposableWrapper(private val disposable: coil.request.Disposable) : io.reactivex.disposables .Disposable { From 199ba4be34d5c6950143c63735f496c2de8978bf Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 21 Nov 2024 15:07:57 +0100 Subject: [PATCH 10/12] add grey avatar with first letter of email-guest in call view Signed-off-by: Marcel Hibbe --- .../talk/adapters/ParticipantDisplayItem.java | 4 ++++ .../nextcloud/talk/adapters/ParticipantsAdapter.java | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java index b4bc87c56..122fd090a 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java @@ -172,6 +172,10 @@ public class ParticipantDisplayItem { return raisedHand; } + public Participant.ActorType getActorType() { + return actorType; + } + public void addObserver(Observer observer) { participantDisplayItemNotifier.addObserver(observer); } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java index 38f334122..2275a7f7d 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantsAdapter.java @@ -22,6 +22,7 @@ import android.widget.TextView; import com.nextcloud.talk.R; import com.nextcloud.talk.activities.CallActivity; import com.nextcloud.talk.extensions.ImageViewExtensionsKt; +import com.nextcloud.talk.models.json.participants.Participant; import org.webrtc.MediaStream; import org.webrtc.MediaStreamTrack; @@ -143,7 +144,15 @@ public class ParticipantsAdapter extends BaseAdapter { nickTextView.setVisibility(View.VISIBLE); nickTextView.setText(participantDisplayItem.getNick()); } - ImageViewExtensionsKt.loadAvatarWithUrl(imageView,null, participantDisplayItem.getUrlForAvatar()); + if (participantDisplayItem.getActorType() == Participant.ActorType.GUESTS || + participantDisplayItem.getActorType() == Participant.ActorType.EMAILS) { + ImageViewExtensionsKt.loadFirstLetterAvatar( + imageView, + String.valueOf(participantDisplayItem.getNick().charAt(0)) + ); + } else { + ImageViewExtensionsKt.loadAvatarWithUrl(imageView,null, participantDisplayItem.getUrlForAvatar()); + } } ImageView audioOffView = convertView.findViewById(R.id.remote_audio_off); From 16d03a69ff3cc8c348ac1441dc57682d59f773ac Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 21 Nov 2024 17:59:43 +0100 Subject: [PATCH 11/12] show guest "first letter" avatars in chat also: create ChatMessageUtils as helper for the ViewHolders in this case. Could help to avoid duplicated code until there is a clear inheritance solution. Signed-off-by: Marcel Hibbe --- .../messages/IncomingDeckCardViewHolder.kt | 16 +------- .../IncomingLinkPreviewMessageViewHolder.kt | 16 +------- .../messages/IncomingPollMessageViewHolder.kt | 16 +------- .../messages/IncomingTextMessageViewHolder.kt | 18 ++------- .../IncomingVoiceMessageViewHolder.kt | 16 +------- .../nextcloud/talk/utils/ChatMessageUtils.kt | 37 +++++++++++++++++++ 6 files changed, 49 insertions(+), 70 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/utils/ChatMessageUtils.kt diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt index aad20fdb3..771001cca 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingDeckCardViewHolder.kt @@ -31,6 +31,7 @@ import com.nextcloud.talk.extensions.loadChangelogBotAvatar import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences @@ -168,7 +169,7 @@ class IncomingDeckCardViewHolder(incomingView: View, payload: Any) : MessageHold } if (!message.isGrouped && !message.isOneToOneConversation && !message.isFormerOneToOneConversation) { - setAvatarOnMessage(message) + ChatMessageUtils().setAvatarOnMessage(binding.messageUserAvatar, message, viewThemeUtils) } else { if (message.isOneToOneConversation || message.isFormerOneToOneConversation) { binding.messageUserAvatar.visibility = View.GONE @@ -179,19 +180,6 @@ class IncomingDeckCardViewHolder(incomingView: View, payload: Any) : MessageHold } } - private fun setAvatarOnMessage(message: ChatMessage) { - binding.messageUserAvatar.visibility = View.VISIBLE - if (message.actorType == "guests") { - // do nothing, avatar is set - } else if (message.actorType == "bots" && message.actorId == "changelog") { - binding.messageUserAvatar.loadChangelogBotAvatar() - } else if (message.actorType == "bots") { - binding.messageUserAvatar.loadBotsAvatar() - } else if (message.actorType == "federated_users") { - binding.messageUserAvatar.loadFederatedUserAvatar(message) - } - } - private fun colorizeMessageBubble(message: ChatMessage) { viewThemeUtils.talk.themeIncomingMessageBubble(bubble, message.isGrouped, message.isDeleted) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt index 0657113f7..53f6506a6 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt @@ -28,6 +28,7 @@ import com.nextcloud.talk.extensions.loadChangelogBotAvatar import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences @@ -146,7 +147,7 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : } if (!message.isGrouped && !message.isOneToOneConversation && !message.isFormerOneToOneConversation) { - setAvatarOnMessage(message) + ChatMessageUtils().setAvatarOnMessage(binding.messageUserAvatar, message, viewThemeUtils) } else { if (message.isOneToOneConversation || message.isFormerOneToOneConversation) { binding.messageUserAvatar.visibility = View.GONE @@ -157,19 +158,6 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : } } - private fun setAvatarOnMessage(message: ChatMessage) { - binding.messageUserAvatar.visibility = View.VISIBLE - if (message.actorType == "guests") { - // do nothing, avatar is set - } else if (message.actorType == "bots" && message.actorId == "changelog") { - binding.messageUserAvatar.loadChangelogBotAvatar() - } else if (message.actorType == "bots") { - binding.messageUserAvatar.loadBotsAvatar() - } else if (message.actorType == "federated_users") { - binding.messageUserAvatar.loadFederatedUserAvatar(message) - } - } - private fun colorizeMessageBubble(message: ChatMessage) { viewThemeUtils.talk.themeIncomingMessageBubble(bubble, message.isGrouped, message.isDeleted) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt index cd8a46824..59b626df8 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt @@ -28,6 +28,7 @@ import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.polls.ui.PollMainDialogFragment import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences @@ -153,7 +154,7 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : } if (!message.isGrouped && !message.isOneToOneConversation && !message.isFormerOneToOneConversation) { - setAvatarOnMessage(message) + ChatMessageUtils().setAvatarOnMessage(binding.messageUserAvatar, message, viewThemeUtils) } else { if (message.isOneToOneConversation || message.isFormerOneToOneConversation) { binding.messageUserAvatar.visibility = View.GONE @@ -164,19 +165,6 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : } } - private fun setAvatarOnMessage(message: ChatMessage) { - binding.messageUserAvatar.visibility = View.VISIBLE - if (message.actorType == "guests") { - // do nothing, avatar is set - } else if (message.actorType == "bots" && message.actorId == "changelog") { - binding.messageUserAvatar.loadChangelogBotAvatar() - } else if (message.actorType == "bots") { - binding.messageUserAvatar.loadBotsAvatar() - } else if (message.actorType == "federated_users") { - binding.messageUserAvatar.loadFederatedUserAvatar(message) - } - } - private fun colorizeMessageBubble(message: ChatMessage) { viewThemeUtils.talk.themeIncomingMessageBubble(bubble, message.isGrouped, message.isDeleted) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt index 6a8ea3280..f71b6f150 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt @@ -26,9 +26,12 @@ import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding import com.nextcloud.talk.extensions.loadBotsAvatar import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadDefaultAvatar import com.nextcloud.talk.extensions.loadFederatedUserAvatar +import com.nextcloud.talk.extensions.loadFirstLetterAvatar import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.TextMatchers import com.nextcloud.talk.utils.message.MessageUtils @@ -153,7 +156,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } if (!message.isGrouped && !message.isOneToOneConversation && !message.isFormerOneToOneConversation) { - setAvatarOnMessage(message) + ChatMessageUtils().setAvatarOnMessage(binding.messageUserAvatar, message, viewThemeUtils) } else { if (message.isOneToOneConversation || message.isFormerOneToOneConversation) { binding.messageUserAvatar.visibility = View.GONE @@ -164,19 +167,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } } - private fun setAvatarOnMessage(message: ChatMessage) { - binding.messageUserAvatar.visibility = View.VISIBLE - if (message.actorType == "guests") { - // do nothing, avatar is set - } else if (message.actorType == "bots" && message.actorId == "changelog") { - binding.messageUserAvatar.loadChangelogBotAvatar() - } else if (message.actorType == "bots") { - binding.messageUserAvatar.loadBotsAvatar() - } else if (message.actorType == "federated_users") { - binding.messageUserAvatar.loadFederatedUserAvatar(message) - } - } - private fun colorizeMessageBubble(message: ChatMessage) { viewThemeUtils.talk.themeIncomingMessageBubble(bubble, message.isGrouped, message.isDeleted) } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 0ba927370..36155bf09 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -32,6 +32,7 @@ import com.nextcloud.talk.extensions.loadChangelogBotAvatar import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ChatMessageUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences @@ -249,7 +250,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : } if (!message.isGrouped && !message.isOneToOneConversation && !message.isFormerOneToOneConversation) { - setAvatarOnMessage(message) + ChatMessageUtils().setAvatarOnMessage(binding.messageUserAvatar, message, viewThemeUtils) } else { if (message.isOneToOneConversation || message.isFormerOneToOneConversation) { binding.messageUserAvatar.visibility = View.GONE @@ -260,19 +261,6 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : } } - private fun setAvatarOnMessage(message: ChatMessage) { - binding.messageUserAvatar.visibility = View.VISIBLE - if (message.actorType == "guests") { - // do nothing, avatar is set - } else if (message.actorType == "bots" && message.actorId == "changelog") { - binding.messageUserAvatar.loadChangelogBotAvatar() - } else if (message.actorType == "bots") { - binding.messageUserAvatar.loadBotsAvatar() - } else if (message.actorType == "federated_users") { - binding.messageUserAvatar.loadFederatedUserAvatar(message) - } - } - private fun colorizeMessageBubble(message: ChatMessage) { viewThemeUtils.talk.themeIncomingMessageBubble(bubble, message.isGrouped, message.isDeleted) } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ChatMessageUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ChatMessageUtils.kt new file mode 100644 index 000000000..92a8827d8 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/ChatMessageUtils.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2024 Marcel Hibbe + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.utils + +import android.view.View +import android.widget.ImageView +import com.nextcloud.talk.chat.data.model.ChatMessage +import com.nextcloud.talk.extensions.loadBotsAvatar +import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadDefaultAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar +import com.nextcloud.talk.extensions.loadFirstLetterAvatar +import com.nextcloud.talk.ui.theme.ViewThemeUtils + +class ChatMessageUtils { + + fun setAvatarOnMessage(view: ImageView, message: ChatMessage, viewThemeUtils : ViewThemeUtils) { + view.visibility = View.VISIBLE + if (message.actorType == "guests" || message.actorType == "emails") { + if (message.actorDisplayName?.isNotEmpty() == true) { + view.loadFirstLetterAvatar(message.actorDisplayName?.first().toString()) + } else { + view.loadDefaultAvatar(viewThemeUtils) + } + } else if (message.actorType == "bots" && message.actorId == "changelog") { + view.loadChangelogBotAvatar() + } else if (message.actorType == "bots") { + view.loadBotsAvatar() + } else if (message.actorType == "federated_users") { + view.loadFederatedUserAvatar(message) + } + } +} From 8e08d9279dd9fc1175a5bb16be1bf6b38abad2a4 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Thu, 21 Nov 2024 18:00:16 +0100 Subject: [PATCH 12/12] remove unused method Signed-off-by: Marcel Hibbe --- .../messages/IncomingTextMessageViewHolder.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt index f71b6f150..b3565de23 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt @@ -242,17 +242,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } } - private fun showAvatarOnChatMessage(message: ChatMessage) { - binding.messageUserAvatar.visibility = View.VISIBLE - if (message.actorType == "guests") { - // do nothing, avatar is set - } else if (message.actorType == "bots" && message.actorId == "changelog") { - binding.messageUserAvatar.loadChangelogBotAvatar() - } else if (message.actorType == "bots") { - binding.messageUserAvatar.loadBotsAvatar() - } - } - fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) { this.commonMessageInterface = commonMessageInterface }