From 1617ec0ec421282452bfc3f5b2b52febc8145379 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 18 Jan 2024 22:31:48 +0100 Subject: [PATCH] Support custom font family for codeblocks and inline code on Android (#133) --- .../livemarkdown/MarkdownFontFamilySpan.java | 36 ++++++++++++++++--- .../MarkdownTextInputDecoratorView.java | 6 ++-- .../expensify/livemarkdown/MarkdownUtils.java | 11 ++++-- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/expensify/livemarkdown/MarkdownFontFamilySpan.java b/android/src/main/java/com/expensify/livemarkdown/MarkdownFontFamilySpan.java index a948f1a8..facecb82 100644 --- a/android/src/main/java/com/expensify/livemarkdown/MarkdownFontFamilySpan.java +++ b/android/src/main/java/com/expensify/livemarkdown/MarkdownFontFamilySpan.java @@ -1,11 +1,39 @@ package com.expensify.livemarkdown; -import android.text.style.TypefaceSpan; +import android.content.res.AssetManager; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.text.TextPaint; +import android.text.style.MetricAffectingSpan; import androidx.annotation.NonNull; -public class MarkdownFontFamilySpan extends TypefaceSpan implements MarkdownSpan { - public MarkdownFontFamilySpan(@NonNull String fontFamily) { - super(fontFamily); +import com.facebook.react.views.text.ReactFontManager; + +public class MarkdownFontFamilySpan extends MetricAffectingSpan implements MarkdownSpan { + + private final @NonNull String mFontFamily; + private final @NonNull AssetManager mAssetManager; + + public MarkdownFontFamilySpan(@NonNull String fontFamily, @NonNull AssetManager assetManager) { + mFontFamily = fontFamily; + mAssetManager = assetManager; + } + + @Override + public void updateMeasureState(@NonNull TextPaint textPaint) { + apply(textPaint); + } + + @Override + public void updateDrawState(TextPaint tp) { + apply(tp); + } + + private void apply(@NonNull TextPaint textPaint) { + int style = textPaint.getTypeface().getStyle(); + Typeface typeface = ReactFontManager.getInstance().getTypeface(mFontFamily, style, mAssetManager); + textPaint.setTypeface(typeface); + textPaint.setFlags(textPaint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG); } } diff --git a/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java b/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java index a17bb0a5..9ea57457 100644 --- a/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java +++ b/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java @@ -3,6 +3,7 @@ import androidx.annotation.Nullable; import android.content.Context; +import android.content.res.AssetManager; import android.text.TextWatcher; import android.util.AttributeSet; @@ -51,8 +52,9 @@ protected void onAttachedToWindow() { } if (previousSibling instanceof ReactEditText) { - MarkdownUtils.maybeInitializeRuntime(getContext().getAssets()); - mMarkdownUtils = new MarkdownUtils(); + AssetManager assetManager = getContext().getAssets(); + MarkdownUtils.maybeInitializeRuntime(assetManager); + mMarkdownUtils = new MarkdownUtils(assetManager); mMarkdownUtils.setMarkdownStyle(mMarkdownStyle); mReactEditText = (ReactEditText) previousSibling; mTextWatcher = new MarkdownTextWatcher(mMarkdownUtils); diff --git a/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java b/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java index 686e61e5..5ab87bfb 100644 --- a/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java +++ b/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; +import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.views.text.CustomLineHeightSpan; @@ -56,6 +57,12 @@ private static String parseMarkdown(String input) { private static native String nativeParseMarkdown(String input); + public MarkdownUtils(@NonNull AssetManager assetManager) { + mAssetManager = assetManager; + } + + private final @NonNull AssetManager mAssetManager; + private String mPrevInput; private String mPrevOutput; @@ -124,12 +131,12 @@ private void applyRange(SpannableStringBuilder ssb, String type, int start, int setSpan(ssb, new MarkdownForegroundColorSpan(mMarkdownStyle.getLinkColor()), start, end); break; case "code": - setSpan(ssb, new MarkdownFontFamilySpan(mMarkdownStyle.getCodeFontFamily()), start, end); + setSpan(ssb, new MarkdownFontFamilySpan(mMarkdownStyle.getCodeFontFamily(), mAssetManager), start, end); setSpan(ssb, new MarkdownForegroundColorSpan(mMarkdownStyle.getCodeColor()), start, end); setSpan(ssb, new MarkdownBackgroundColorSpan(mMarkdownStyle.getCodeBackgroundColor()), start, end); break; case "pre": - setSpan(ssb, new MarkdownFontFamilySpan(mMarkdownStyle.getPreFontFamily()), start, end); + setSpan(ssb, new MarkdownFontFamilySpan(mMarkdownStyle.getPreFontFamily(), mAssetManager), start, end); setSpan(ssb, new MarkdownForegroundColorSpan(mMarkdownStyle.getPreColor()), start, end); setSpan(ssb, new MarkdownBackgroundColorSpan(mMarkdownStyle.getPreBackgroundColor()), start, end); break;