From 870ef03d61e204e5d9055b138d1524103c1c1547 Mon Sep 17 00:00:00 2001 From: Julius Linus <julius.linus@nextcloud.com> Date: Fri, 8 Mar 2024 11:21:09 -0600 Subject: [PATCH] Federated Mentions - Federated mention chip - Federated message avatars - Helper functions Signed-off-by: Julius Linus <julius.linus@nextcloud.com> --- .../items/MentionAutocompleteItem.java | 58 ++++++++++++++----- .../IncomingLinkPreviewMessageViewHolder.kt | 3 + .../IncomingLocationMessageViewHolder.kt | 3 + .../messages/IncomingPollMessageViewHolder.kt | 3 + .../messages/IncomingTextMessageViewHolder.kt | 3 + .../IncomingVoiceMessageViewHolder.kt | 3 + .../messages/PreviewMessageViewHolder.kt | 3 + .../MentionAutocompleteCallback.java | 21 ++++--- .../com/nextcloud/talk/chat/ChatActivity.kt | 2 + .../talk/extensions/ImageViewExtensions.kt | 42 ++++++++++++++ .../talk/models/json/chat/ChatMessage.kt | 4 +- .../talk/models/json/mention/Mention.kt | 9 ++- .../MentionAutocompletePresenter.java | 6 ++ .../java/com/nextcloud/talk/utils/ApiUtils.kt | 13 +++++ .../nextcloud/talk/utils/DisplayUtils.java | 31 +++++++--- .../talk/utils/message/MessageUtils.kt | 13 ++++- 16 files changed, 181 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java index 62cc33510..610758002 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java @@ -58,8 +58,10 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte public static final String SOURCE_GUESTS = "guests"; public static final String SOURCE_GROUPS = "groups"; + public static final String SOURCE_FEDERATION = "federated_users"; private String source; + private final String mentionId; private final String objectId; private final String displayName; private final String status; @@ -67,12 +69,14 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte private final String statusMessage; private final User currentUser; private final Context context; + private final String roomToken; private final ViewThemeUtils viewThemeUtils; public MentionAutocompleteItem( Mention mention, User currentUser, - Context activityContext, ViewThemeUtils viewThemeUtils) { + Context activityContext, String roomToken, ViewThemeUtils viewThemeUtils) { + this.mentionId = mention.getMentionId(); this.objectId = mention.getId(); this.displayName = mention.getLabel(); this.source = mention.getSource(); @@ -82,6 +86,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte this.currentUser = currentUser; this.context = activityContext; this.viewThemeUtils = viewThemeUtils; + this.roomToken = roomToken; } public String getSource() { @@ -92,6 +97,10 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte this.source = source; } + public String getMentionId() { + return mentionId; + } + public String getObjectId() { return objectId; } @@ -100,6 +109,10 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte return displayName; } + public String getRoomToken() { + return roomToken; + } + @Override public boolean equals(Object o) { if (o instanceof MentionAutocompleteItem inItem) { @@ -147,24 +160,39 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte holder.binding.secondaryText.setText("@" + objectId); } - if (SOURCE_CALLS.equals(source) || SOURCE_GROUPS.equals(source)) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - ImageViewExtensionsKt.loadUserAvatar( - holder.binding.avatarView, - viewThemeUtils.talk.themePlaceholderAvatar( + String avatarId = objectId; + switch (source) { + case SOURCE_CALLS: {} + case SOURCE_GROUPS: { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + ImageViewExtensionsKt.loadUserAvatar( holder.binding.avatarView, - R.drawable.ic_avatar_group - ) - ); - } else { - ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView, R.drawable.ic_circular_group); + viewThemeUtils.talk.themePlaceholderAvatar( + holder.binding.avatarView, + R.drawable.ic_avatar_group)); + } else { + ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView, R.drawable.ic_circular_group); + } + break; } - } else { - String avatarId = objectId; - if (SOURCE_GUESTS.equals(source)) { + case SOURCE_FEDERATION: { + int darkTheme = (DisplayUtils.isDarkModeOn(this.context))? 1 : 0; + ImageViewExtensionsKt.loadFederatedUserAvatar(holder.binding.avatarView, + currentUser, + Objects.requireNonNull(currentUser.getBaseUrl()), + roomToken, + avatarId, + darkTheme, + true, + false); + break; + } + case SOURCE_GUESTS: { avatarId = displayName; } - ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView, currentUser, avatarId, true, false); + default: { + ImageViewExtensionsKt.loadUserAvatar(holder.binding.avatarView, currentUser, avatarId, true, false); + } } drawStatus(holder); 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 ed2662ff9..713361aff 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 @@ -37,6 +37,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedA import com.nextcloud.talk.databinding.ItemCustomIncomingLinkPreviewMessageBinding import com.nextcloud.talk.extensions.loadBotsAvatar import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils @@ -172,6 +173,8 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : binding.messageUserAvatar.loadChangelogBotAvatar() } else if (message.actorType == "bots") { binding.messageUserAvatar.loadBotsAvatar() + } else if (message.actorType == "federated_users" && message.messageParameters?.get("actor") != null) { + binding.messageUserAvatar.loadFederatedUserAvatar(message) } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt index aa9ab400c..6185aa8e9 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt @@ -47,6 +47,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedA import com.nextcloud.talk.databinding.ItemCustomIncomingLocationMessageBinding import com.nextcloud.talk.extensions.loadBotsAvatar import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils @@ -148,6 +149,8 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : binding.messageUserAvatar.loadChangelogBotAvatar() } else if (message.actorType == "bots") { binding.messageUserAvatar.loadBotsAvatar() + } else if (message.actorType == "federated_users" && message.messageParameters?.get("actor") != null) { + binding.messageUserAvatar.loadFederatedUserAvatar(message) } } else { if (message.isOneToOneConversation || message.isFormerOneToOneConversation) { 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 a3ee9c61e..becb6858b 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 @@ -36,6 +36,7 @@ import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.databinding.ItemCustomIncomingPollMessageBinding import com.nextcloud.talk.extensions.loadBotsAvatar import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.polls.ui.PollMainDialogFragment import com.nextcloud.talk.ui.theme.ViewThemeUtils @@ -179,6 +180,8 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : binding.messageUserAvatar.loadChangelogBotAvatar() } else if (message.actorType == "bots") { binding.messageUserAvatar.loadBotsAvatar() + } else if (message.actorType == "federated_users" && message.messageParameters?.get("actor") != null) { + binding.messageUserAvatar.loadFederatedUserAvatar(message) } } 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 1bfb832df..bb0b3d018 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 @@ -41,6 +41,7 @@ import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding import com.nextcloud.talk.extensions.loadBotsAvatar import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils @@ -182,6 +183,8 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : binding.messageUserAvatar.loadChangelogBotAvatar() } else if (message.actorType == "bots") { binding.messageUserAvatar.loadBotsAvatar() + } else if (message.actorType == "federated_users" && message.messageParameters?.get("actor") != null) { + binding.messageUserAvatar.loadFederatedUserAvatar(message) } } 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 e09bae1fb..929f54407 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 @@ -45,6 +45,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.databinding.ItemCustomIncomingVoiceMessageBinding import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils @@ -285,6 +286,8 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : ) binding.messageUserAvatar.visibility = View.VISIBLE binding.messageUserAvatar.setImageDrawable(drawable) + } else if (message.actorType == "federated_users" && message.messageParameters?.get("actor") != null) { + binding.messageUserAvatar.loadFederatedUserAvatar(message) } } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/PreviewMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/PreviewMessageViewHolder.kt index 6674240fb..ee21d703e 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/PreviewMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/PreviewMessageViewHolder.kt @@ -49,6 +49,7 @@ import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding import com.nextcloud.talk.extensions.loadChangelogBotAvatar +import com.nextcloud.talk.extensions.loadFederatedUserAvatar import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.users.UserManager @@ -194,6 +195,8 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) : } if (ACTOR_TYPE_BOTS == message.actorType && ACTOR_ID_CHANGELOG == message.actorId) { userAvatar.loadChangelogBotAvatar() + } else if (message.actorType == "federated_users" && message.messageParameters?.get("actor") != null) { + userAvatar.loadFederatedUserAvatar(message) } } } diff --git a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java index fe8434393..87f85c048 100644 --- a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java +++ b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java @@ -27,7 +27,6 @@ import android.text.Editable; import android.text.Spanned; import android.widget.EditText; -import third.parties.fresco.BetterImageSpan; import com.nextcloud.talk.R; import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.models.json.mention.Mention; @@ -39,7 +38,10 @@ import com.otaliastudios.autocomplete.AutocompleteCallback; import com.vanniktech.emoji.EmojiRange; import com.vanniktech.emoji.Emojis; +import java.util.Objects; + import kotlin.OptIn; +import third.parties.fresco.BetterImageSpan; public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> { private final ViewThemeUtils viewThemeUtils; @@ -66,26 +68,31 @@ public class MentionAutocompleteCallback implements AutocompleteCallback<Mention } String replacement = item.getLabel(); - StringBuilder replacementStringBuilder = new StringBuilder(item.getLabel()); + StringBuilder replacementStringBuilder = new StringBuilder(Objects.requireNonNull(item.getLabel())); for (EmojiRange emojiRange : Emojis.emojis(replacement)) { replacementStringBuilder.delete(emojiRange.range.getStart(), emojiRange.range.getEndInclusive()); } - editable.replace(range.getStart(), range.getEnd(), replacementStringBuilder + " "); + String charSequence = " "; + editable.replace(range.getStart(), range.getEnd(), charSequence + replacementStringBuilder + " "); + String id; + if (item.getMentionId() != null) id = item.getMentionId(); else id = item.getId(); Spans.MentionChipSpan mentionChipSpan = new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context, item.getId(), + item.getRoomToken(), item.getLabel(), conversationUser, item.getSource(), R.xml.chip_you, editText, - viewThemeUtils), + viewThemeUtils, + "federated_users".equals(item.getSource())), BetterImageSpan.ALIGN_CENTER, - item.getId(), item.getLabel()); + id, item.getLabel()); editable.setSpan(mentionChipSpan, - range.getStart(), - range.getStart() + replacementStringBuilder.length(), + range.getStart() + charSequence.length(), + range.getStart() + replacementStringBuilder.length() + charSequence.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt index bfbb0ee3b..518bddde0 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt @@ -3584,6 +3584,7 @@ class ChatActivity : mentionSpan = mentionSpans[i] var mentionId = mentionSpan.id if (mentionId.contains(" ") || + mentionId.contains("@") || mentionId.startsWith("guest/") || mentionId.startsWith("group/") ) { @@ -3798,6 +3799,7 @@ class ChatActivity : chatMessage.isFormerOneToOneConversation = (currentConversation?.type == ConversationType.FORMER_ONE_TO_ONE) chatMessage.activeUser = conversationUser + chatMessage.roomToken = roomToken } if (adapter != null) { 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 377d51d1f..ce52114aa 100644 --- a/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt @@ -46,6 +46,7 @@ import com.nextcloud.talk.R import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.domain.ConversationType +import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils @@ -126,6 +127,47 @@ fun ImageView.loadUserAvatar( return loadAvatarInternal(user, imageRequestUri, ignoreCache, null) } +fun ImageView.loadFederatedUserAvatar(message: ChatMessage): io.reactivex.disposables.Disposable { + val map = message.messageParameters?.get("actor") + val url = map?.get("server")!! + val id = map["id"] + val cloudId = "$id@$url" + val darkTheme = if (DisplayUtils.isDarkModeOn(context)) 1 else 0 + val ignoreCache = false + val requestBigSize = true + return loadFederatedUserAvatar( + message.activeUser!!, + message.activeUser!!.baseUrl!!, + message.roomToken, + cloudId, + darkTheme, + requestBigSize, + ignoreCache + ) +} + +@Suppress("LongParameterList") +fun ImageView.loadFederatedUserAvatar( + user: User, + baseUrl: String, + token: String, + cloudId: String, + darkTheme: Int, + requestBigSize: Boolean = true, + ignoreCache: Boolean +): io.reactivex.disposables.Disposable { + val imageRequestUri = ApiUtils.getUrlForFederatedAvatar( + baseUrl, + token, + cloudId, + darkTheme, + requestBigSize + ) + Log.d("Julius", "URL::$imageRequestUri") + + return loadAvatarInternal(user, imageRequestUri, ignoreCache, null) +} + @OptIn(ExperimentalCoilApi::class) private fun ImageView.loadAvatarInternal( user: User?, diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt index dc285504c..2b04036ea 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.kt @@ -159,7 +159,9 @@ data class ChatMessage( var hiddenByCollapse: Boolean = false, - var openWhenDownloaded: Boolean = true + var openWhenDownloaded: Boolean = true, + + var roomToken: String = "" ) : Parcelable, MessageContentType, MessageContentType.Image { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.kt b/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.kt index 740c72fe9..c449104c5 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.kt @@ -23,12 +23,15 @@ package com.nextcloud.talk.models.json.mention import android.os.Parcelable import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonIgnore import com.bluelinelabs.logansquare.annotation.JsonObject import kotlinx.parcelize.Parcelize @Parcelize @JsonObject data class Mention( + @JsonField(name = ["mentionId"]) + var mentionId: String?, @JsonField(name = ["id"]) var id: String?, @JsonField(name = ["label"]) @@ -41,8 +44,10 @@ data class Mention( @JsonField(name = ["statusIcon"]) var statusIcon: String?, @JsonField(name = ["statusMessage"]) - var statusMessage: String? + var statusMessage: String?, + @JsonIgnore + var roomToken: String? ) : Parcelable { // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' - constructor() : this(null, null, null, null, null, null) + constructor() : this(null, null, null, null, null, null, null, null) } diff --git a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java index c11eb27b4..06e9fde2d 100644 --- a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java +++ b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java @@ -155,6 +155,7 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention> mention, currentUser, context, + roomToken, viewThemeUtils)); } @@ -185,9 +186,14 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention> Mention mention = new Mention(); MentionAutocompleteItem mentionAutocompleteItem = (MentionAutocompleteItem) adapter.getItem(position); if (mentionAutocompleteItem != null) { + String mentionId = mentionAutocompleteItem.getMentionId(); + if(mentionId != null) { + mention.setMentionId(mentionId); + } mention.setId(mentionAutocompleteItem.getObjectId()); mention.setLabel(mentionAutocompleteItem.getDisplayName()); mention.setSource(mentionAutocompleteItem.getSource()); + mention.setRoomToken(mentionAutocompleteItem.getRoomToken()); dispatchClick(mention); } return true; diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt index 82092a00c..a5b5613e5 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -383,6 +383,19 @@ object ApiUtils { return baseUrl + "/index.php/avatar/" + Uri.encode(name) + "/" + avatarSize } + @JvmStatic + fun getUrlForFederatedAvatar( + baseUrl: String, + token: String, + cloudId: String, + darkTheme: Int, + requestBigSize: Boolean + ): String { + val avatarSize = if (requestBigSize) AVATAR_SIZE_BIG else AVATAR_SIZE_SMALL + val url = "$baseUrl$OCS_API_VERSION$SPREED_API_VERSION/proxy/$token/user-avatar/$avatarSize" + return "$url?cloudId=$cloudId&darkTheme=$darkTheme" + } + @JvmStatic fun getUrlForGuestAvatar(baseUrl: String?, name: String?, requestBigSize: Boolean): String { val avatarSize = if (requestBigSize) AVATAR_SIZE_BIG else AVATAR_SIZE_SMALL diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index c964645e8..3e2c392c8 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -68,6 +68,7 @@ import org.greenrobot.eventbus.EventBus; import java.text.DateFormat; import java.util.Date; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -168,12 +169,14 @@ public class DisplayUtils { public static Drawable getDrawableForMentionChipSpan(Context context, String id, + String roomToken, CharSequence label, User conversationUser, String type, @XmlRes int chipResource, @Nullable EditText emojiEditText, - ViewThemeUtils viewThemeUtils) { + ViewThemeUtils viewThemeUtils, + Boolean isFederated) { ChipDrawable chip = ChipDrawable.createFromResource(context, chipResource); chip.setText(EmojiCompat.get().process(label)); chip.setEllipsize(TextUtils.TruncateAt.MIDDLE); @@ -205,13 +208,21 @@ public class DisplayUtils { chip.setBounds(0, 0, chip.getIntrinsicWidth(), chip.getIntrinsicHeight()); if (!isCallOrGroup) { - String url = ApiUtils.getUrlForAvatar(conversationUser.getBaseUrl(), id, true); + String url = ApiUtils.getUrlForAvatar(conversationUser.getBaseUrl(), id, false); if ("guests".equals(type) || "guest".equals(type)) { url = ApiUtils.getUrlForGuestAvatar( conversationUser.getBaseUrl(), String.valueOf(label), true); } + if (isFederated) { + int darkTheme = (DisplayUtils.isDarkModeOn(context))? 1 : 0; + url = ApiUtils.getUrlForFederatedAvatar(Objects.requireNonNull(conversationUser.getBaseUrl()), + roomToken, id, + darkTheme, false); + } + + ImageRequest imageRequest = new ImageRequest.Builder(context) .data(url) .crossfade(true) @@ -224,13 +235,12 @@ public class DisplayUtils { @Override public void onError(@Nullable Drawable drawable) { - + chip.setChipIcon(drawable); } @Override public void onSuccess(@NonNull Drawable drawable) { chip.setChipIcon(drawable); - // A hack to refresh the chip icon if (emojiEditText != null) { emojiEditText.post(() -> emojiEditText.setTextKeepState( @@ -248,10 +258,12 @@ public class DisplayUtils { } public static Spannable searchAndReplaceWithMentionSpan(String key, Context context, Spanned text, - String id, String label, String type, + String id, String roomToken, + String label, String type, User conversationUser, @XmlRes int chipXmlRes, - ViewThemeUtils viewThemeUtils) { + ViewThemeUtils viewThemeUtils, + Boolean isFederated) { Spannable spannableString = new SpannableString(text); String stringText = text.toString(); @@ -267,7 +279,7 @@ public class DisplayUtils { } }; - int lastStartIndex = -1; + int lastStartIndex = 0; Spans.MentionChipSpan mentionChipSpan; while (m.find()) { int start = stringText.indexOf(m.group(), lastStartIndex); @@ -276,13 +288,14 @@ public class DisplayUtils { Drawable drawableForChip = DisplayUtils.getDrawableForMentionChipSpan(context, id, + roomToken, label, conversationUser, type, chipXmlRes, null, - viewThemeUtils); - + viewThemeUtils, + isFederated); mentionChipSpan = new Spans.MentionChipSpan(drawableForChip, BetterImageSpan.ALIGN_CENTER, id, 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 786d9f7f4..cb8787746 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 @@ -127,16 +127,24 @@ class MessageUtils(val context: Context) { } else { R.xml.chip_others } + val id = if (individualHashMap["server"] != null) { + individualHashMap["id"] + "@" + individualHashMap["server"] + } else { + individualHashMap["id"] + } + messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan( key, themingContext, messageStringInternal, - individualHashMap["id"]!!, + id, + message.roomToken, individualHashMap["name"]!!, individualHashMap["type"]!!, message.activeUser!!, chip, - viewThemeUtils + viewThemeUtils, + individualHashMap["server"] != null ) } @@ -174,5 +182,6 @@ class MessageUtils(val context: Context) { companion object { private const val TAG = "MessageUtils" const val MAX_REPLY_LENGTH = 250 + const val HTTPS_PROTOCOL = "https://" } }