From 7003a4ff4fd264550174c3eefe529e80a3b1e63b Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Thu, 18 Oct 2018 13:45:02 +0200 Subject: [PATCH] Improve chat display --- Habitica/res/layout/tavern_chat_item.xml | 3 +- Habitica/res/values/colors.contributor.xml | 2 +- .../habitica/ui/helpers/MarkdownParser.kt | 24 ++++-- .../habitica/ui/helpers/UsernameSpan.java | 76 +++++++++++++++++++ .../habitica/ui/views/social/UsernameLabel.kt | 1 + 5 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/UsernameSpan.java diff --git a/Habitica/res/layout/tavern_chat_item.xml b/Habitica/res/layout/tavern_chat_item.xml index 1ef82e420..50870f290 100644 --- a/Habitica/res/layout/tavern_chat_item.xml +++ b/Habitica/res/layout/tavern_chat_item.xml @@ -99,7 +99,8 @@ android:layout_height="wrap_content" android:layout_margin="8dp" android:lineSpacingMultiplier="1.0" - tools:text="This is the chat message"/> + tools:text="This is the chat message" + android:textColor="@color/gray_10"/> - #aaa + #4e4a57 #c42871 #b01515 #d70e14 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt index 6940aa207..a8fe1167d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/MarkdownParser.kt @@ -1,5 +1,6 @@ package com.habitrpg.android.habitica.ui.helpers +import android.graphics.Color import android.text.Html import com.commonsware.cwac.anddown.AndDown @@ -7,11 +8,16 @@ import com.commonsware.cwac.anddown.AndDown import net.pherth.android.emoji_library.EmojiParser import android.text.Html.FROM_HTML_MODE_LEGACY +import android.text.SpannableStringBuilder +import android.text.Spanned +import android.text.style.ForegroundColorSpan +import android.text.style.StyleSpan import com.habitrpg.android.habitica.helpers.RxErrorHandler import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers +import java.util.regex.Pattern /** * @author data5tream @@ -20,6 +26,9 @@ object MarkdownParser { private val processor = AndDown() + private val regex = Pattern.compile("@(?:\\w+)") + private val colorSpan = UsernameSpan() + /** * Parses formatted markdown and returns it as styled CharSequence * @@ -30,14 +39,19 @@ object MarkdownParser { if (input == null) { return "" } - var output: CharSequence = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { - Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim { it <= ' ' })), FROM_HTML_MODE_LEGACY) + val output: SpannableStringBuilder = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim { it <= ' ' })), FROM_HTML_MODE_LEGACY) as? SpannableStringBuilder } else { @Suppress("DEPRECATION") - Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim { it <= ' ' }))) + (Html.fromHtml(processor.markdownToHtml(EmojiParser.parseEmojis(input.trim { it <= ' ' }))) as? SpannableStringBuilder) + } ?: SpannableStringBuilder() + + val matcher = regex.matcher(output) + while (matcher.find()) { + output.setSpan(colorSpan, matcher.start(), matcher.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } - if (output.length >= 2) output = output.subSequence(0, output.length - 2) - return output + + return if (output.length >= 2) output.subSequence(0, output.length - 2) else output } fun parseMarkdownAsync(input: String?, onSuccess: Consumer) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/UsernameSpan.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/UsernameSpan.java new file mode 100644 index 000000000..4fb2a9498 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/helpers/UsernameSpan.java @@ -0,0 +1,76 @@ +package com.habitrpg.android.habitica.ui.helpers; + +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.os.Parcel; +import android.support.annotation.NonNull; +import android.text.ParcelableSpan; +import android.text.TextPaint; +import android.text.style.MetricAffectingSpan; + +public class UsernameSpan extends MetricAffectingSpan implements ParcelableSpan { + + private final int color = Color.parseColor("#6133b4"); + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + private void writeToParcelInternal(@NonNull Parcel dest, int flags) { + dest.writeInt(color); + } + + public void updateDrawState(@NonNull TextPaint textPaint) { + textPaint.setColor(color); + apply(textPaint); + } + + @Override + public int getSpanTypeId() { + return 0; + } + + @Override + public void updateMeasureState(@NonNull TextPaint textPaint) { + apply(textPaint); + } + + private static void apply(Paint paint) { + int oldStyle; + + Typeface old = paint.getTypeface(); + if (old == null) { + oldStyle = 0; + } else { + oldStyle = old.getStyle(); + } + + int want = oldStyle | Typeface.BOLD; + + Typeface tf; + if (old == null) { + tf = Typeface.defaultFromStyle(want); + } else { + tf = Typeface.create(old, want); + } + + int fake = want & ~tf.getStyle(); + + if ((fake & Typeface.BOLD) != 0) { + paint.setFakeBoldText(true); + } + + if ((fake & Typeface.ITALIC) != 0) { + paint.setTextSkewX(-0.25f); + } + + paint.setTypeface(tf); + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/UsernameLabel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/UsernameLabel.kt index ef6335d97..8e72b536f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/UsernameLabel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/UsernameLabel.kt @@ -43,6 +43,7 @@ class UsernameLabel(context: Context?, attrs: AttributeSet?) : LinearLayout(cont addView(textView, params) val padding = context?.resources?.getDimension(R.dimen.spacing_small)?.toInt() ?: 0 textView.setPadding(0, 0, padding, 0) + textView. addView(tierIconView, params) } } \ No newline at end of file