diff --git a/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java b/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java index e97a1acc..46c9d27d 100644 --- a/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java +++ b/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java @@ -41,10 +41,7 @@ public CustomMountingManager( @NonNull ReadableMap decoratorProps, int parserId) { super(viewManagerRegistry, mountItemExecutor); - - AssetManager assetManager = context.getAssets(); - - this.markdownUtils = new MarkdownUtils(assetManager); + this.markdownUtils = new MarkdownUtils((ReactContext) context); this.markdownUtils.setMarkdownStyle(new MarkdownStyle(decoratorProps, context)); this.markdownUtils.setParserId(parserId); } diff --git a/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java b/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java index 2ea25ce4..6bd1a68f 100644 --- a/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java +++ b/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java @@ -11,6 +11,7 @@ import android.view.ViewGroup; import android.view.ViewParent; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.views.textinput.ReactEditText; public class MarkdownTextInputDecoratorView extends View { @@ -54,8 +55,7 @@ protected void onAttachedToWindow() { } if (previousSibling instanceof ReactEditText) { - AssetManager assetManager = getContext().getAssets(); - mMarkdownUtils = new MarkdownUtils(assetManager); + mMarkdownUtils = new MarkdownUtils((ReactContext) getContext()); mMarkdownUtils.setMarkdownStyle(mMarkdownStyle); mMarkdownUtils.setParserId(mParserId); mReactEditText = (ReactEditText) previousSibling; diff --git a/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java b/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java index 72e7928c..a385ee31 100644 --- a/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java +++ b/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java @@ -7,6 +7,8 @@ import androidx.annotation.NonNull; import com.expensify.livemarkdown.spans.*; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.util.RNLog; import com.facebook.react.views.text.internal.span.CustomLineHeightSpan; import com.facebook.soloader.SoLoader; @@ -14,8 +16,6 @@ import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; -import java.io.InputStream; import java.util.Objects; public class MarkdownUtils { @@ -25,10 +25,12 @@ public class MarkdownUtils { private static synchronized native String nativeParseMarkdown(String input, int parserId); - public MarkdownUtils(@NonNull AssetManager assetManager) { - mAssetManager = assetManager; + public MarkdownUtils(@NonNull ReactContext reactContext) { + mReactContext = reactContext; + mAssetManager = reactContext.getAssets(); } + private final @NonNull ReactContext mReactContext; private final @NonNull AssetManager mAssetManager; private String mPrevInput; @@ -77,7 +79,7 @@ public void applyMarkdownFormatting(SpannableStringBuilder ssb) { applyRange(ssb, type, start, end, depth); } } catch (JSONException e) { - // Do nothing + RNLog.w(mReactContext, "[react-native-live-markdown] Incorrect schema of worklet parser output: " + e.getMessage()); } } diff --git a/apple/RCTMarkdownUtils.mm b/apple/RCTMarkdownUtils.mm index 844c83c5..4072ed1b 100644 --- a/apple/RCTMarkdownUtils.mm +++ b/apple/RCTMarkdownUtils.mm @@ -33,44 +33,46 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA auto markdownWorklet = expensify::livemarkdown::getMarkdownWorklet([_parserId intValue]); - auto text = jsi::String::createFromUtf8(rt, [inputString UTF8String]); - auto output = markdownRuntime->runGuarded(markdownWorklet, text); - if (output.isUndefined()) { - return input; - } - const auto &ranges = output.asObject(rt).asArray(rt); + try { + const auto &text = jsi::String::createFromUtf8(rt, [inputString UTF8String]); + const auto &output = markdownRuntime->runGuarded(markdownWorklet, text); + const auto &ranges = output.asObject(rt).asArray(rt); - NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes]; - [attributedString beginEditing]; + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes]; + [attributedString beginEditing]; - // If the attributed string ends with underlined text, blurring the single-line input imprints the underline style across the whole string. - // It looks like a bug in iOS, as there is no underline style to be found in the attributed string, especially after formatting. - // This is a workaround that applies the NSUnderlineStyleNone to the string before iterating over ranges which resolves this problem. - [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(0, attributedString.length)]; + // If the attributed string ends with underlined text, blurring the single-line input imprints the underline style across the whole string. + // It looks like a bug in iOS, as there is no underline style to be found in the attributed string, especially after formatting. + // This is a workaround that applies the NSUnderlineStyleNone to the string before iterating over ranges which resolves this problem. + [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(0, attributedString.length)]; - _blockquoteRangesAndLevels = [NSMutableArray new]; + _blockquoteRangesAndLevels = [NSMutableArray new]; - for (size_t i = 0, n = ranges.size(rt); i < n; ++i) { - const auto &item = ranges.getValueAtIndex(rt, i).asObject(rt); - const auto &type = item.getProperty(rt, "type").asString(rt).utf8(rt); - const auto &start = static_cast(item.getProperty(rt, "start").asNumber()); - const auto &length = static_cast(item.getProperty(rt, "length").asNumber()); - const auto &depth = item.hasProperty(rt, "depth") ? static_cast(item.getProperty(rt, "depth").asNumber()) : 1; + for (size_t i = 0, n = ranges.size(rt); i < n; ++i) { + const auto &item = ranges.getValueAtIndex(rt, i).asObject(rt); + const auto &type = item.getProperty(rt, "type").asString(rt).utf8(rt); + const auto &start = static_cast(item.getProperty(rt, "start").asNumber()); + const auto &length = static_cast(item.getProperty(rt, "length").asNumber()); + const auto &depth = item.hasProperty(rt, "depth") ? static_cast(item.getProperty(rt, "depth").asNumber()) : 1; - [self applyRangeToAttributedString:attributedString type:type start:start length:length depth:depth]; - } + [self applyRangeToAttributedString:attributedString type:type start:start length:length depth:depth]; + } - RCTApplyBaselineOffset(attributedString); + RCTApplyBaselineOffset(attributedString); - [attributedString endEditing]; + [attributedString endEditing]; - _prevInputString = inputString; - _prevAttributedString = attributedString; - _prevTextAttributes = attributes; - _prevMarkdownStyle = _markdownStyle; - _prevParserId = _parserId; + _prevInputString = inputString; + _prevAttributedString = attributedString; + _prevTextAttributes = attributes; + _prevMarkdownStyle = _markdownStyle; + _prevParserId = _parserId; - return attributedString; + return attributedString; + } catch (const jsi::JSError &error) { + RCTLogWarn(@"[react-native-live-markdown] Incorrect schema of worklet parser output: %s", error.getMessage().c_str()); + return input; + } } }