/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.views.text.frescosupport;
import javax.annotation.Nullable;
import java.util.Locale;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import com.facebook.common.util.UriUtil;
import com.facebook.yoga.YogaConstants;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.text.ReactTextInlineImageShadowNode;
import com.facebook.react.views.text.TextInlineImageSpan;
/**
* Shadow node that represents an inline image. Loading is done using Fresco.
*
*/
public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShadowNode {
private @Nullable Uri mUri;
private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
private final @Nullable Object mCallerContext;
private float mWidth = YogaConstants.UNDEFINED;
private float mHeight = YogaConstants.UNDEFINED;
public FrescoBasedReactTextInlineImageShadowNode(
AbstractDraweeControllerBuilder draweeControllerBuilder,
@Nullable Object callerContext) {
mDraweeControllerBuilder = draweeControllerBuilder;
mCallerContext = callerContext;
}
@ReactProp(name = "src")
public void setSource(@Nullable ReadableArray sources) {
final String source =
(sources == null || sources.size() == 0) ? null : sources.getMap(0).getString("uri");
Uri uri = null;
if (source != null) {
try {
uri = Uri.parse(source);
// Verify scheme is set, so that relative uri (used by static resources) are not handled.
if (uri.getScheme() == null) {
uri = null;
}
} catch (Exception e) {
// ignore malformed uri, then attempt to extract resource ID.
}
if (uri == null) {
uri = getResourceDrawableUri(getThemedContext(), source);
}
}
if (uri != mUri) {
markUpdated();
}
mUri = uri;
}
/**
* Besides width/height, all other layout props on inline images are ignored
*/
@Override
public void setWidth(float width) {
mWidth = width;
}
@Override
public void setHeight(float height) {
mHeight = height;
}
public @Nullable Uri getUri() {
return mUri;
}
// TODO: t9053573 is tracking that this code should be shared
private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
if (name == null || name.isEmpty()) {
return null;
}
name = name.toLowerCase(Locale.getDefault()).replace("-", "_");
int resId = context.getResources().getIdentifier(
name,
"drawable",
context.getPackageName());
return new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
.path(String.valueOf(resId))
.build();
}
@Override
public boolean isVirtual() {
return true;
}
@Override
public TextInlineImageSpan buildInlineImageSpan() {
Resources resources = getThemedContext().getResources();
int height = (int) Math.ceil(mWidth);
int width = (int) Math.ceil(mHeight);
return new FrescoBasedReactTextInlineImageSpan(
resources,
height,
width,
getUri(),
getDraweeControllerBuilder(),
getCallerContext());
}
public AbstractDraweeControllerBuilder getDraweeControllerBuilder() {
return mDraweeControllerBuilder;
}
public @Nullable Object getCallerContext() {
return mCallerContext;
}
}