From 61912740a8672185df2aefada1fb787c80c7eb27 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Wed, 5 Mar 2025 09:14:07 +0100 Subject: [PATCH 1/7] Show avatars in activity list Signed-off-by: tobiasKaminsky --- .../java/com/nextcloud/utils/text/Spans.java | 82 ++++++++++++ .../third_parties/fresco/BetterImageSpan.kt | 117 ++++++++++++++++++ app/src/main/res/drawable/accent_circle.xml | 10 ++ .../main/res/layout/activity_list_item.xml | 6 +- app/src/main/res/values/dims.xml | 1 + app/src/main/res/xml/chip_others.xml | 13 ++ 6 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/utils/text/Spans.java create mode 100644 app/src/main/java/third_parties/fresco/BetterImageSpan.kt create mode 100644 app/src/main/res/drawable/accent_circle.xml create mode 100644 app/src/main/res/xml/chip_others.xml diff --git a/app/src/main/java/com/nextcloud/utils/text/Spans.java b/app/src/main/java/com/nextcloud/utils/text/Spans.java new file mode 100644 index 000000000000..098366292ccb --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/text/Spans.java @@ -0,0 +1,82 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2021 Andy Scherzinger + * SPDX-FileCopyrightText: 2017-2018 Mario Danic + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.utils.text; + +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import thirdparties.fresco.BetterImageSpan; + +public class Spans { + + public static class MentionChipSpan extends BetterImageSpan { + public String id; + public CharSequence label; + + public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, CharSequence label) { + super(drawable, verticalAlignment); + this.id = id; + this.label = label; + } + + public String getId() { + return this.id; + } + + public CharSequence getLabel() { + return this.label; + } + + public void setId(String id) { + this.id = id; + } + + public void setLabel(CharSequence label) { + this.label = label; + } + + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof MentionChipSpan)) { + return false; + } + final MentionChipSpan other = (MentionChipSpan) o; + if (!other.canEqual((Object) this)) { + return false; + } + final Object this$id = this.getId(); + final Object other$id = other.getId(); + if (this$id == null ? other$id != null : !this$id.equals(other$id)) { + return false; + } + final Object this$label = this.getLabel(); + final Object other$label = other.getLabel(); + + return this$label == null ? other$label == null : this$label.equals(other$label); + } + + protected boolean canEqual(final Object other) { + return other instanceof MentionChipSpan; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $id = this.getId(); + result = result * PRIME + ($id == null ? 43 : $id.hashCode()); + final Object $label = this.getLabel(); + return result * PRIME + ($label == null ? 43 : $label.hashCode()); + } + + public String toString() { + return "Spans.MentionChipSpan(id=" + this.getId() + ", label=" + this.getLabel() + ")"; + } + } +} diff --git a/app/src/main/java/third_parties/fresco/BetterImageSpan.kt b/app/src/main/java/third_parties/fresco/BetterImageSpan.kt new file mode 100644 index 000000000000..3996cca94945 --- /dev/null +++ b/app/src/main/java/third_parties/fresco/BetterImageSpan.kt @@ -0,0 +1,117 @@ +/* + * SPDX-FileCopyrightText: 2015-present, Facebook, Inc. and its affiliates. + * SPDX-License-Identifier: MIT + */ + +package thirdparties.fresco + +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.text.style.ReplacementSpan +import androidx.annotation.IntDef + +/** + * A better implementation of image spans that also supports centering images against the text. + * + * In order to migrate from ImageSpan, replace `new ImageSpan(drawable, alignment)` with + * `new BetterImageSpan(drawable, BetterImageSpan.normalizeAlignment(alignment))`. + * + * There are 2 main differences between BetterImageSpan and ImageSpan: + * 1. Pass in ALIGN_CENTER to center images against the text. + * 2. ALIGN_BOTTOM no longer unnecessarily increases the size of the text: + * DynamicDrawableSpan (ImageSpan's parent) adjusts sizes as if alignment was ALIGN_BASELINE + * which can lead to unnecessary whitespace. + */ +open class BetterImageSpan @JvmOverloads constructor( + val drawable: Drawable, + @param:BetterImageSpanAlignment private val mAlignment: Int = ALIGN_BASELINE +) : ReplacementSpan() { + @Suppress("Detekt.SpreadOperator") + @IntDef(*[ALIGN_BASELINE, ALIGN_BOTTOM, ALIGN_CENTER]) + @Retention(AnnotationRetention.SOURCE) + annotation class BetterImageSpanAlignment + + private var mWidth = 0 + private var mHeight = 0 + private var mBounds: Rect? = null + private val mFontMetricsInt = Paint.FontMetricsInt() + + init { + updateBounds() + } + + /** + * Returns the width of the image span and increases the height if font metrics are available. + */ + override fun getSize( + paint: Paint, + text: CharSequence, + start: Int, + end: Int, + fontMetrics: Paint.FontMetricsInt? + ): Int { + updateBounds() + if (fontMetrics == null) { + return mWidth + } + val offsetAbove = getOffsetAboveBaseline(fontMetrics) + val offsetBelow = mHeight + offsetAbove + if (offsetAbove < fontMetrics.ascent) { + fontMetrics.ascent = offsetAbove + } + if (offsetAbove < fontMetrics.top) { + fontMetrics.top = offsetAbove + } + if (offsetBelow > fontMetrics.descent) { + fontMetrics.descent = offsetBelow + } + if (offsetBelow > fontMetrics.bottom) { + fontMetrics.bottom = offsetBelow + } + return mWidth + } + + override fun draw( + canvas: Canvas, + text: CharSequence, + start: Int, + end: Int, + x: Float, + top: Int, + y: Int, + bottom: Int, + paint: Paint + ) { + paint.getFontMetricsInt(mFontMetricsInt) + val iconTop = y + getOffsetAboveBaseline(mFontMetricsInt) + canvas.translate(x, iconTop.toFloat()) + drawable.draw(canvas) + canvas.translate(-x, -iconTop.toFloat()) + } + + private fun updateBounds() { + mBounds = drawable.bounds + mWidth = mBounds!!.width() + mHeight = mBounds!!.height() + } + + private fun getOffsetAboveBaseline(fm: Paint.FontMetricsInt): Int = when (mAlignment) { + ALIGN_BOTTOM -> fm.descent - mHeight + ALIGN_CENTER -> { + val textHeight = fm.descent - fm.ascent + val offset = (textHeight - mHeight) / 2 + fm.ascent + offset + } + + ALIGN_BASELINE -> -mHeight + else -> -mHeight + } + + companion object { + const val ALIGN_BOTTOM = 0 + const val ALIGN_BASELINE = 1 + const val ALIGN_CENTER = 2 + } +} diff --git a/app/src/main/res/drawable/accent_circle.xml b/app/src/main/res/drawable/accent_circle.xml new file mode 100644 index 000000000000..3acd7c33c465 --- /dev/null +++ b/app/src/main/res/drawable/accent_circle.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/layout/activity_list_item.xml b/app/src/main/res/layout/activity_list_item.xml index ad17d9e40485..4e0bb51d201c 100644 --- a/app/src/main/res/layout/activity_list_item.xml +++ b/app/src/main/res/layout/activity_list_item.xml @@ -34,11 +34,13 @@ 3dp 16dp 10dp + 12dp 72dp 0dp 56dp diff --git a/app/src/main/res/xml/chip_others.xml b/app/src/main/res/xml/chip_others.xml new file mode 100644 index 000000000000..9f878b3edb22 --- /dev/null +++ b/app/src/main/res/xml/chip_others.xml @@ -0,0 +1,13 @@ + + From 2cf36d158b8526cc9e356933efd2cb6f5c5392ee Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 17 Feb 2026 12:09:59 +0100 Subject: [PATCH 2/7] Rename .java to .kt Signed-off-by: tobiasKaminsky --- .../main/java/com/nextcloud/utils/text/{Spans.java => Spans.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/nextcloud/utils/text/{Spans.java => Spans.kt} (100%) diff --git a/app/src/main/java/com/nextcloud/utils/text/Spans.java b/app/src/main/java/com/nextcloud/utils/text/Spans.kt similarity index 100% rename from app/src/main/java/com/nextcloud/utils/text/Spans.java rename to app/src/main/java/com/nextcloud/utils/text/Spans.kt From 986d84e4fe514a89fdb4a159fa1324f94bd872bf Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 17 Feb 2026 12:09:59 +0100 Subject: [PATCH 3/7] fix spotless Signed-off-by: tobiasKaminsky --- .../java/com/nextcloud/utils/text/Spans.kt | 91 +++++++------------ .../third_parties/fresco/BetterImageSpan.kt | 2 + 2 files changed, 34 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/text/Spans.kt b/app/src/main/java/com/nextcloud/utils/text/Spans.kt index 098366292ccb..c2c76e7abed1 100644 --- a/app/src/main/java/com/nextcloud/utils/text/Spans.kt +++ b/app/src/main/java/com/nextcloud/utils/text/Spans.kt @@ -5,78 +5,51 @@ * SPDX-FileCopyrightText: 2017-2018 Mario Danic * SPDX-License-Identifier: GPL-3.0-or-later */ -package com.nextcloud.utils.text; +package com.nextcloud.utils.text -import android.graphics.drawable.Drawable; +import android.graphics.drawable.Drawable +import thirdparties.fresco.BetterImageSpan -import androidx.annotation.NonNull; -import thirdparties.fresco.BetterImageSpan; - -public class Spans { - - public static class MentionChipSpan extends BetterImageSpan { - public String id; - public CharSequence label; - - public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, CharSequence label) { - super(drawable, verticalAlignment); - this.id = id; - this.label = label; - } - - public String getId() { - return this.id; - } - - public CharSequence getLabel() { - return this.label; - } - - public void setId(String id) { - this.id = id; - } - - public void setLabel(CharSequence label) { - this.label = label; - } - - public boolean equals(final Object o) { - if (o == this) { - return true; +class Spans { + class MentionChipSpan(drawable: Drawable, verticalAlignment: Int, var id: String, var label: CharSequence?) : + BetterImageSpan(drawable, verticalAlignment) { + override fun equals(o: Any?): Boolean { + if (o === this) { + return true } - if (!(o instanceof MentionChipSpan)) { - return false; + if (o !is MentionChipSpan) { + return false } - final MentionChipSpan other = (MentionChipSpan) o; - if (!other.canEqual((Object) this)) { - return false; + val other = o + if (!other.canEqual(this as Any)) { + return false } - final Object this$id = this.getId(); - final Object other$id = other.getId(); - if (this$id == null ? other$id != null : !this$id.equals(other$id)) { - return false; + val `this$id`: Any? = this.id + val `other$id`: Any? = other.id + if (if (`this$id` == null) `other$id` != null else (`this$id` != `other$id`)) { + return false } - final Object this$label = this.getLabel(); - final Object other$label = other.getLabel(); + val `this$label`: Any? = this.label + val `other$label`: Any? = other.label - return this$label == null ? other$label == null : this$label.equals(other$label); + return if (`this$label` == null) `other$label` == null else (`this$label` == `other$label`) } - protected boolean canEqual(final Object other) { - return other instanceof MentionChipSpan; + protected fun canEqual(other: Any?): Boolean { + return other is MentionChipSpan } - public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $id = this.getId(); - result = result * PRIME + ($id == null ? 43 : $id.hashCode()); - final Object $label = this.getLabel(); - return result * PRIME + ($label == null ? 43 : $label.hashCode()); + override fun hashCode(): Int { + val PRIME = 59 + var result = 1 + val `$id`: Any? = this.id + result = result * PRIME + (if (`$id` == null) 43 else `$id`.hashCode()) + val `$label`: Any? = this.label + return result * PRIME + (if (`$label` == null) 43 else `$label`.hashCode()) } - public String toString() { - return "Spans.MentionChipSpan(id=" + this.getId() + ", label=" + this.getLabel() + ")"; + override fun toString(): String { + return "Spans.MentionChipSpan(id=" + this.id + ", label=" + this.label + ")" } } } diff --git a/app/src/main/java/third_parties/fresco/BetterImageSpan.kt b/app/src/main/java/third_parties/fresco/BetterImageSpan.kt index 3996cca94945..da8a0bfff4a0 100644 --- a/app/src/main/java/third_parties/fresco/BetterImageSpan.kt +++ b/app/src/main/java/third_parties/fresco/BetterImageSpan.kt @@ -99,6 +99,7 @@ open class BetterImageSpan @JvmOverloads constructor( private fun getOffsetAboveBaseline(fm: Paint.FontMetricsInt): Int = when (mAlignment) { ALIGN_BOTTOM -> fm.descent - mHeight + ALIGN_CENTER -> { val textHeight = fm.descent - fm.ascent val offset = (textHeight - mHeight) / 2 @@ -106,6 +107,7 @@ open class BetterImageSpan @JvmOverloads constructor( } ALIGN_BASELINE -> -mHeight + else -> -mHeight } From 9acc468783369b276cdd467bdb817a110a846538 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 17 Feb 2026 12:25:36 +0100 Subject: [PATCH 4/7] fix detekt Signed-off-by: tobiasKaminsky --- .../java/com/nextcloud/utils/text/Spans.kt | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/text/Spans.kt b/app/src/main/java/com/nextcloud/utils/text/Spans.kt index c2c76e7abed1..9ca42fe8a74e 100644 --- a/app/src/main/java/com/nextcloud/utils/text/Spans.kt +++ b/app/src/main/java/com/nextcloud/utils/text/Spans.kt @@ -24,32 +24,28 @@ class Spans { if (!other.canEqual(this as Any)) { return false } - val `this$id`: Any? = this.id - val `other$id`: Any? = other.id - if (if (`this$id` == null) `other$id` != null else (`this$id` != `other$id`)) { + val thisId: Any? = this.id + val otherId: Any? = other.id + if (if (thisId == null) otherId != null else (thisId != otherId)) { return false } - val `this$label`: Any? = this.label - val `other$label`: Any? = other.label + val thisLabel: Any? = this.label + val otherLabel: Any? = other.label - return if (`this$label` == null) `other$label` == null else (`this$label` == `other$label`) + return if (thisLabel == null) otherLabel == null else (thisLabel == otherLabel) } - protected fun canEqual(other: Any?): Boolean { - return other is MentionChipSpan - } + protected fun canEqual(other: Any?): Boolean = other is MentionChipSpan override fun hashCode(): Int { - val PRIME = 59 + val prime = 59 var result = 1 - val `$id`: Any? = this.id - result = result * PRIME + (if (`$id` == null) 43 else `$id`.hashCode()) - val `$label`: Any? = this.label - return result * PRIME + (if (`$label` == null) 43 else `$label`.hashCode()) + val thisId: Any? = this.id + result = result * prime + (if (thisId == null) 43 else thisId.hashCode()) + val label: Any? = this.label + return result * prime + (if (label == null) 43 else label.hashCode()) } - override fun toString(): String { - return "Spans.MentionChipSpan(id=" + this.id + ", label=" + this.label + ")" - } + override fun toString(): String = "Spans.MentionChipSpan(id=" + this.id + ", label=" + this.label + ")" } } From 055fd3ebc50ab7849677b407a99307a78010eba3 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Fri, 17 Jul 2026 10:39:50 +0200 Subject: [PATCH 5/7] wip Signed-off-by: tobiasKaminsky --- .../activities/adapter/ActivityListAdapter.kt | 110 +++++++++++++----- app/src/main/res/values/styles.xml | 4 + 2 files changed, 86 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt index 2ae062e338f4..d3b1fa145597 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/activities/adapter/ActivityListAdapter.kt @@ -8,12 +8,13 @@ package com.owncloud.android.ui.activities.adapter import android.content.Context import android.graphics.Typeface +import android.graphics.drawable.Drawable import android.text.Spannable import android.text.SpannableStringBuilder import android.text.TextPaint +import android.text.TextUtils import android.text.format.DateFormat import android.text.format.DateUtils -import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan import android.text.style.ForegroundColorSpan import android.text.style.StyleSpan @@ -27,10 +28,12 @@ import androidx.annotation.DrawableRes import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.chip.ChipDrawable import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.common.NextcloudClient import com.nextcloud.utils.GlideHelper +import com.nextcloud.utils.text.Spans.MentionChipSpan import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.ActivityListItemBinding @@ -49,6 +52,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import thirdparties.fresco.BetterImageSpan import java.util.Locale import kotlin.math.floor import kotlin.math.log @@ -62,7 +66,8 @@ open class ActivityListAdapter( private val isDetailView: Boolean, private val viewThemeUtils: ViewThemeUtils ) : RecyclerView.Adapter(), - StickyHeaderAdapter { + StickyHeaderAdapter, + DisplayUtils.AvatarGenerationListener { protected var client: NextcloudClient? = null val values: MutableList = mutableListOf() @@ -113,9 +118,10 @@ open class ActivityListAdapter( when { activity.richSubjectElement.richSubject.isNotEmpty() -> holder.binding.subject.apply { - visibility = View.VISIBLE - movementMethod = LinkMovementMethod.getInstance() - setText(addClickablePart(activity.richSubjectElement), TextView.BufferType.SPANNABLE) + text = addClickablePart(activity.richSubjectElement) + // visibility = View.VISIBLE + // movementMethod = LinkMovementMethod.getInstance() + // setText(addClickablePart(activity.richSubjectElement), TextView.BufferType.SPANNABLE) } activity.subject.isNotEmpty() -> holder.binding.subject.apply { @@ -176,6 +182,19 @@ open class ActivityListAdapter( } } + fun getDrawableForMentionChipSpan(chipResource: Int, text: String): ChipDrawable { + val chip = ChipDrawable.createFromResource(context, chipResource).apply { + setEllipsize(TextUtils.TruncateAt.MIDDLE) + setLayoutDirection(context.getResources().getConfiguration().getLayoutDirection()) + setText(text) + setChipIconResource(R.drawable.accent_circle) + } + + chip.setBounds(0, 0, chip.getIntrinsicWidth(), chip.getIntrinsicHeight()) + + return chip + } + private suspend fun nextcloudClient(): NextcloudClient = withContext(Dispatchers.IO) { OwnCloudClientManagerFactory.getDefaultSingleton() .getNextcloudClientFor(currentAccountProvider.user.toOwnCloudAccount(), context) @@ -224,6 +243,7 @@ open class ActivityListAdapter( return imageView } + @Suppress("NestedBlockDepth") private fun addClickablePart(richElement: RichElement): SpannableStringBuilder { var text = richElement.richSubject val ssb = SpannableStringBuilder(text) @@ -236,29 +256,57 @@ open class ActivityListAdapter( } if (richObject != null) { - val name = richObject.name.orEmpty() - ssb.replace(idx1, idx2, name) - text = ssb.toString() - idx2 = idx1 + name.length - - ssb.setSpan( - object : ClickableSpan() { - override fun onClick(widget: View) = activityListInterface.onActivityClicked(richObject) - override fun updateDrawState(ds: TextPaint) { - ds.isUnderlineText = false - } - }, - idx1, - idx2, - 0 - ) - ssb.setSpan(StyleSpan(Typeface.BOLD), idx1, idx2, 0) - ssb.setSpan( - ForegroundColorSpan(context.resources.getColor(R.color.text_color)), - idx1, - idx2, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) + if ("user".equals(richObject.type)) { + val name = richObject.name + + val drawableForChip = getDrawableForMentionChipSpan(R.xml.chip_others, name ?: "") + + val mentionChipSpan = MentionChipSpan( + drawableForChip, + BetterImageSpan.ALIGN_CENTER, + richObject.id ?: "", + name + ) + + if (richObject.id != null) { + DisplayUtils.setAvatar( + currentAccountProvider.user, + richObject.id!!, + name, + this, + context.resources.getDimension(R.dimen.avatar_icon_radius), + context.resources, + drawableForChip, + context + ) + } + + ssb.setSpan(mentionChipSpan, idx1, idx2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + } else { + val name = richObject.name.orEmpty() + ssb.replace(idx1, idx2, name) + text = ssb.toString() + idx2 = idx1 + name.length + + ssb.setSpan( + object : ClickableSpan() { + override fun onClick(widget: View) = activityListInterface.onActivityClicked(richObject) + override fun updateDrawState(ds: TextPaint) { + ds.isUnderlineText = false + } + }, + idx1, + idx2, + 0 + ) + ssb.setSpan(StyleSpan(Typeface.BOLD), idx1, idx2, 0) + ssb.setSpan( + ForegroundColorSpan(context.resources.getColor(R.color.text_color)), + idx1, + idx2, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } } idx1 = text.indexOf('{', idx2) } @@ -308,6 +356,12 @@ open class ActivityListAdapter( override fun isHeader(itemPosition: Int) = itemPosition in values.indices && getItemViewType(itemPosition) == HEADER_TYPE + override fun avatarGenerated(avatarDrawable: Drawable, callContext: Any) { + (callContext as ChipDrawable).chipIcon = avatarDrawable + } + + override fun shouldCallGeneratedCallback(tag: String, callContext: Any): Boolean = true + protected class ActivityViewHolder(val binding: ActivityListItemBinding) : RecyclerView.ViewHolder(binding.root) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 3b9d1ef0ecb9..58c63b7577be 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -490,4 +490,8 @@ @android:color/black @color/primary + + From 3454b7a7ccc54254fe2517b738ca233ce1fb2562 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Wed, 5 Mar 2025 09:14:07 +0100 Subject: [PATCH 6/7] Show avatars in activity list Signed-off-by: tobiasKaminsky # Conflicts: # app/src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java # app/src/main/java/third_parties/fresco/BetterImageSpan.kt # app/src/main/res/values/styles.xml --- .../java/com/nextcloud/utils/text/Spans.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/utils/text/Spans.java diff --git a/app/src/main/java/com/nextcloud/utils/text/Spans.java b/app/src/main/java/com/nextcloud/utils/text/Spans.java new file mode 100644 index 000000000000..098366292ccb --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/text/Spans.java @@ -0,0 +1,82 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2021 Andy Scherzinger + * SPDX-FileCopyrightText: 2017-2018 Mario Danic + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.utils.text; + +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import thirdparties.fresco.BetterImageSpan; + +public class Spans { + + public static class MentionChipSpan extends BetterImageSpan { + public String id; + public CharSequence label; + + public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, CharSequence label) { + super(drawable, verticalAlignment); + this.id = id; + this.label = label; + } + + public String getId() { + return this.id; + } + + public CharSequence getLabel() { + return this.label; + } + + public void setId(String id) { + this.id = id; + } + + public void setLabel(CharSequence label) { + this.label = label; + } + + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof MentionChipSpan)) { + return false; + } + final MentionChipSpan other = (MentionChipSpan) o; + if (!other.canEqual((Object) this)) { + return false; + } + final Object this$id = this.getId(); + final Object other$id = other.getId(); + if (this$id == null ? other$id != null : !this$id.equals(other$id)) { + return false; + } + final Object this$label = this.getLabel(); + final Object other$label = other.getLabel(); + + return this$label == null ? other$label == null : this$label.equals(other$label); + } + + protected boolean canEqual(final Object other) { + return other instanceof MentionChipSpan; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $id = this.getId(); + result = result * PRIME + ($id == null ? 43 : $id.hashCode()); + final Object $label = this.getLabel(); + return result * PRIME + ($label == null ? 43 : $label.hashCode()); + } + + public String toString() { + return "Spans.MentionChipSpan(id=" + this.getId() + ", label=" + this.getLabel() + ")"; + } + } +} From ebee2f30fbe125e12ffb9e7fdbae78dd4141e447 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 17 Jul 2026 16:04:20 +0200 Subject: [PATCH 7/7] remove old Spans.java Signed-off-by: alperozturk96 --- .../java/com/nextcloud/utils/text/Spans.java | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/utils/text/Spans.java diff --git a/app/src/main/java/com/nextcloud/utils/text/Spans.java b/app/src/main/java/com/nextcloud/utils/text/Spans.java deleted file mode 100644 index 098366292ccb..000000000000 --- a/app/src/main/java/com/nextcloud/utils/text/Spans.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2021 Andy Scherzinger - * SPDX-FileCopyrightText: 2017-2018 Mario Danic - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package com.nextcloud.utils.text; - -import android.graphics.drawable.Drawable; - -import androidx.annotation.NonNull; -import thirdparties.fresco.BetterImageSpan; - -public class Spans { - - public static class MentionChipSpan extends BetterImageSpan { - public String id; - public CharSequence label; - - public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, CharSequence label) { - super(drawable, verticalAlignment); - this.id = id; - this.label = label; - } - - public String getId() { - return this.id; - } - - public CharSequence getLabel() { - return this.label; - } - - public void setId(String id) { - this.id = id; - } - - public void setLabel(CharSequence label) { - this.label = label; - } - - public boolean equals(final Object o) { - if (o == this) { - return true; - } - if (!(o instanceof MentionChipSpan)) { - return false; - } - final MentionChipSpan other = (MentionChipSpan) o; - if (!other.canEqual((Object) this)) { - return false; - } - final Object this$id = this.getId(); - final Object other$id = other.getId(); - if (this$id == null ? other$id != null : !this$id.equals(other$id)) { - return false; - } - final Object this$label = this.getLabel(); - final Object other$label = other.getLabel(); - - return this$label == null ? other$label == null : this$label.equals(other$label); - } - - protected boolean canEqual(final Object other) { - return other instanceof MentionChipSpan; - } - - public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $id = this.getId(); - result = result * PRIME + ($id == null ? 43 : $id.hashCode()); - final Object $label = this.getLabel(); - return result * PRIME + ($label == null ? 43 : $label.hashCode()); - } - - public String toString() { - return "Spans.MentionChipSpan(id=" + this.getId() + ", label=" + this.getLabel() + ")"; - } - } -}